题目链接:https://codeforces.com/contest/1702/problem/E
题意
有n张牌,每张牌上写有两个数字,问是否能将牌分成两个集合,使得每个集合中的牌上的数字不重复。
思路
这个题可以用种类并查集的思想,不懂得小伙伴建议先看一下什么是种类并查集
按照数字的值分类,先处理不同的数值分别在哪一张牌上面,例如{1,4},{1,3},{3,2},{4,2},那么包含1数字的牌有第一张和第二张,包含3数字的牌有第二张和第三张。之后用种类并查集的方法遍历每个数值分成的组,看看其中两张牌是否在一个并查集集合中,如果是那么就不能把牌分成两组,反之合并两张牌。
具体代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
const int N=1e6+10;
const int mod=1e9+7;
const db eps=1e-8;
struct node{
int a,b;
}q[N];
struct Node{
int x,y;
}a[N];
vector<int> idx[N];
int fa[N];
int find(int x)
{
return x==fa[x]? x: (fa[x]=find(fa[x]));
}
void merge(int i,int j)
{
fa[find(i)]=find(j);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
int m=0;
for(int i=1;i<=2*n;i++) fa[i]=i;//初始化需要2倍长度
for(int i=1;i<=n;i++) idx[i].clear();
for(int i=1;i<=n;i++)
{
scanf("%d%d",&q[i].a,&q[i].b);
idx[q[i].a].push_back(i);//按照数值把牌分类
idx[q[i].b].push_back(i);
}
bool flag=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<idx[i].size();j++)
{
for(int k=j+1;k<idx[i].size();k++)
{
a[m].x=idx[i][j],a[m++].y=idx[i][k];
}
}
}
for(int i=0;i<m;i++)
{
if(find(a[i].x)==find(a[i].y))
{
flag=0;
break;
}
merge(a[i].x,a[i].y+n),merge(a[i].y,a[i].x+n);//种类并查集合并集合操作
}
if(!flag) puts("NO");
else puts("YES");
}
return 0;
}