//并查集,类似于POJ 1703 //通过维护当前结点与父亲的关系来实现对同性恋的判断 //并查集的分类依据是能否相互确定关系,能相互确定关系的在同一颗树种 #include<iostream> #define MAX 2005 using namespace std; bool ok; int x,y,n,m,k,t; struct node { int parent; int sex;//记录关系,假设0为男,1为女 }set[MAX]; void init()//初始化 { for(int i = 1;i <= n;++i) { set[i].parent = i; set[i].sex = 0; } } int Find(int x) { int px = set[x].parent;//暂时存放父亲 if(x == set[x].parent) return x; else { set[x].parent = Find(set[x].parent);//路径压缩 set[x].sex = (set[px].sex + set[x].sex) % 2;//回溯的时候更新性别,从根结点一直更新到叶子节点 //更新的原因是为了保证让他们之间男女搭配的关系不变,如果x父亲从0变成1,那么x就从1变成0, 上面那条式子就是维护这个关系 } return set[x].parent; } void Union(int x,int y) { int px = Find(x); int py = Find(y); if(px != py)//如果他们的根不同,说明相互无法确定,所以可以合并 { set[px].parent = py; set[px].sex = (set[x].sex + set[y].sex + 1) % 2;//合并后改变另一集合根的性别 //改变的依据是x,y的性别情况,px和py的性别总是为0,现在要把py作为px的爸爸,那么py.sex=0 //所以情况有3种,一、x.sex = y.sex = 1 px.sex = 1 //二、x.sex = y.sex = 0 px.sex = 1 //三、x.sex != y.sex px.sex = 0; //故有上面的递推式 } else { if(set[x].sex == set[y].sex) ok = 0;//如果他们处于共同集合,但性取向相同,那么就是同性恋咯 } } int main() { //freopen("in.txt","r",stdin); int caseN = 0; scanf("%d",&t); while(t--) { ok = 1; scanf("%d%d",&n,&m); init(); while(m--) { scanf("%d%d",&x,&y); Union(x,y); } if(!ok) printf("Scenario #%d:/nSuspicious bugs found!/n/n",++caseN); else printf("Scenario #%d:/nNo suspicious bugs found!/n/n",++caseN); } return 0; }