【多解】UVa 10763 交换学生 Foreign Exchange【附输入数据构造参考代码】

博客主要解析了UVa 10763 交换学生问题的多种解决方案,包括使用映射存储整数对并检查配对一致性,以及通过构建和比较两个有序数组来判断交换可行性。博主提供了三种算法,重点讨论了算法的时间复杂度和实现细节,并分享了构造特殊输入数据的代码。
摘要由CSDN通过智能技术生成

【紫书第五章习题5-4】
开始做这题的时候用的是直接把每一行数对扔进map里然后一行行找是否有调换了两个数的有序整数对,有一个没找到,整个交换都不能进行。结果当然是样例都过不了,因为样例里就出现了第一个数一致但第二个数不同的情况,第二次及以后出现第一个数相同的数对根本无法输入进map中。后来试了multimap,不过写着写着发现写了4重循环(不知道我是不是想太多,写得过于复杂了),便放弃继续深究了,因为循环能到4重基本没有不超时的,准备重新按照新方法写之前随便试了一下,这份用multimap的代码坚持了180 ms然后WA。
今天自己写了一种方法(参见法一),然后结合网上找的题解改进了2个版本,把代码都贴出来供参考学习。
先说题目大意,单次输入包含多组数据,首先每一组输入的第一行是一个整数n,且1≤n≤500 000,代表参加交换生项目的学生总数。接下来n行是每个学生的交换意愿,写成两个整数的形式。整数用空格隔开,分别代表学生所在的原始地区和想去的地区。如果这个交换能进行(输出YES),则要求对于每个想由A地前往B地的学生,必须同时有一个想由B地前往A地的学生参加本次项目,否则整个交换项目失败(输出NO)。n=0时结束输入。所有地点坐标用非负整数表示,且假定每个学生想去的地点与出发地一定不同。

【法一】(约 260 ms。经过数次提交发现,运行时间可能会不一样,也出现过240 ms、290 ms、370 ms。)
算法概述:
将每个有序整数对<x, y>存入映射 f 中,f<x, y>的值是<x, y>的出现次数。输入的<x, y>在 f 中不存在时,添加映射关系
f<x, y>=0,存在时直接将对应的出现次数+1。对 cur 为当前正在输入或查找的有序整数对。
输入完毕后,对任意有序整数对<x0, y0>,若均有 f<x0, y0> == f<y0, x0>,则每个学生都可以配对,交换项目得以进行。否则失败。特别地,查找不到 f<x0, y0>(返回迭代器 f.end())时,也代表有学生无法配对,项目失败。
由于对每个有序实数对 f<x0, y0> 需要1~2次从整个映射中查找:
23行 查找并返回迭代器 it = find(f<x0, y0>)、若找到则判定 f<x0, y0> == f<y0, x0>(f<x0, y0>的位置由迭代器 it 给出,不用再查找),耗时较长。

#include<cstdio>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#pragma warning(disable:4996)
using namespace std; typedef unsigned int uint;
map<pair<uint, uint>, uint> f; pair<uint, uint> cur;
int main() {
   
	uint n; bool verdict; map<pair<uint, uint>, uint>::iterator it;
	for (;;) {
   
		scanf("%u", &n); if (n == 0)break;
		f.clear();
		for (uint i = 0; i < n; ++i) {
   
			scanf("%u%u", &cur.first, &cur.second); 
			it = f.find(cur);
			if (it == f.end())f.emplace(cur, 0);
			else ++(*it).second;
		}
		verdict = true;
		for (map<pair<uint, uint>, uint>::iterator i = f.begin(); i != f.end(); ++i) {
   
			cur.first = (*i).first.second, cur.second = (*i).first.first;
			it = f.find(cur)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值