【2019.4.7】库里FMVP
需要注意的地方:
1、书上翻译的有些问题,每行输入的两个数字分别代表了学校,而不是学生本身,因此允许有下面这样的数据出现(学校1和学校4有两对学生交换,输出YES)
1 4
1 4
4 1
4 1
2、每行的两个数字顺序是固定的,第一个数字是原来的学校,第二个数字是想去的学校
思路整理:
1、对于大量输入数据的题目,有两种思路:
① 一边输入一边对数据做处理,输入完了之后自然得到结果
② 输入全部数据之后,再做处理,得到结果
由于输入数据有500000个之多,第一种可能性更大一些,顺着第一种思路往下想:
2、一边输入,一边对数据需要做哪些处理?
根据题意可知,我们需要判断,对于每一个输入(a,b),是否能找到另一个输入(b,a)与之对应
换句话说,对于每一个输入(a,b),如果我们先将他调换过来形成(b,a),然后再找是否存在另一个(b,a)与之完全相同,这就相当于一个判重问题
3、判重问题
判重问题常常需要一个集合(set),当我们每输入一行(a,b),我们将在集合(set)中查找其调换过来的形式(b,a)
如果在集合中找到了,我们把(b,a)从集合中删去,就好像连连看游戏那样
如果没在集合中找到,我们就把其原形式(a,b)插入集合,等待其他输入数据与其对应
4、选择数据结构
我们需要一个集合,集合的元素是二元组,对于集合的操作是:频繁的插入、删除和查找
首先,对于二元组,有数组、结构体、vector等等形式,其中vector可以作为其他容器的基本元素,况且也定义了各种运算符,因此比较合适
其次,对于集合,我们通常选用set,其特点是:内部排序,插入和删除比较快,查找相对快
然而这道题是不能用set的,因为set里不会出现重复元素,而我们的数据里可能会出现重复的二元组
因此我们选用multiset,它跟set唯一的区别就是,允许有重复元素的存在
5、判断输出结果
输出YES的情况:所有数据输入完毕,集合为空,证明所有元素配对成功
其他情况都输出NO
6、有一些早期判断结果的条件
① 如果n为奇数的话,那么一定输出NO,因为此时不可能配对
② 当还剩下x个二元组没输入,集合中还有y个元素时,如果x<y,那么一定输出NO,因为集合里那y个元素不可能全都找到配对,一定会有剩下的
7、需要注意的问题
当我们用multiset.erase(x)
来删除集合中的x
元素时,集合中所有的x
元素都会被删除,而本题中,我们一次只需要删除其中一个,这时候就要用到iterator
了
代码:
#include <iostream>
#include <set>
#include <map>
#include <vector>
using namespace std;
multiset<vector<int>> s; //判重集合
vector<int> p1; //原始输入
vector<int> poff; //两个数字调过来的输入
int main()
{
//freopen("C:\\Users\\Summer\\Desktop\\input.txt", "r", stdin);
//freopen("C:\\Users\\Summer\\Desktop\\output.txt", "w", stdout);
int n;
bool flag;
while(cin>>n && n) {
flag = true;
s.clear();
//如果有奇数个,永远不可能配对
if(n%2 == 1) flag = false;
//输入
int a, b;
int i;
for(i=0; i<n; i++) {
scanf("%d %d", &a, &b);
//原始的二元组(a,b)
p1.clear(); p1.push_back(a); p1.push_back(b);
//把a和b调换顺序,形成二元组(b,a)
poff.clear(); poff.push_back(b); poff.push_back(a);
//it用于指向待删除元素
multiset<vector<int>>::iterator it;
if(flag) {
//如果配对就移除
if(s.count(poff)) {
it = s.find(poff); //找到集合中与当前输入配对的元素(b,a)
s.erase(it); //删除之
}
//否则就插入
else s.insert(p1); //插入了原始二元组(a,b)
//如果剩下输入的数量比还未配对的数量少,一定输入NO
if(n-i-1 < (int)s.size()) flag = false;
}
}
//当所有输入数据都完事,集合是否为空
if(s.size()) flag = false;
//输出
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}