Problem S
Time Limit : 15000/5000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 3 Accepted Submission(s) : 2
2 3 3 1 2 2 3 1 3 4 2 1 2 3 4
Scenario #1: Suspicious bugs found! Scenario #2: No suspicious bugs found! <div style='font-family:Times New Roman;font-size:14px;background-color:F4FBFF;border:#B7CBFF 1px dashed;padding:6px'><div style='font-family:Arial;font-weight:bold;color:#7CA9ED;border-bottom:#B7CBFF 1px dashed'><i>Hint</i></div>Huge input,scanf is recommended.</div>
做了这题才再次发现自己对并查集的了解真的只是一些皮毛,并查集的很多高级应用我都还不懂,而这题只是种类并查集中最简单的 .
假设有
1,2
2,3
即1--2--3, 明显相邻的两个不能是同性别的,如果相邻两个是同性的,那么说明就可能是有同性恋存在。
上面假设1是男性,用false来代替,那么按顺序分别是false, true, false
假设 再加个关系3, 1
那么由于1和3已经都有值了,都是false,说明可能有同性恋。
种类并查集的关键在于与结点与根结点的距离, 如果距离是奇数那么性别就和跟结点相反,如果是偶数就和跟结点性别相同。
代码:
#include<cstdio>
#define N 2005
using namespace std;
int f[N],rank[N], n, k;
bool flag;
inline void init(){
flag=false;
for(int i=0; i<=n; ++i)
f[i]=i, rank[i]=0;
}
int find(int x){
if(x==f[x])return f[x];
int t=find(f[x]);
rank[x] = (rank[f[x]]+rank[x])&1;
f[x]=t;
return f[x];
}
void Union(int x, int y){
int a=find(x), b=find(y);
if(a==b){
if(rank[x]==rank[y])
flag=true;
return;
}
f[a]=b;
rank[a] = (rank[x]+rank[y]+1)&1;
}
int main(){
int T,a,b,cas=1;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
init();
for(int i=0; i<k; ++i){
scanf("%d%d",&a,&b);
if(flag)continue;
Union(a,b);
}
printf("Scenario #%d:\n",cas++);
if(flag)printf("Suspicious bugs found!\n");
else printf("No suspicious bugs found!\n");
printf("\n");
}
return 0;
}