【紫书第五章习题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)