链接:点击打开链接
题意:给出一个T代表几组数据,给出一个m一个n,代表人的编号由1~m,n条命令,每条命令由两个数值组成,代表这两个人性别不同,问所有命令是否符合逻辑
例如:给出数据为1||3 3||1 2||1 3||2 3,表示1,2性别不同,1,3性别不同,因此可以推断出2,3性别一定相同,但是由给出了2,3因此不符合逻辑
代码:
#include <iostream> #include<algorithm> #include<cstdio> using namespace std; int f[10005],dis[10005]; //dis数组代表该节点与父节点的关系,1代表与父节点性别不同,反之即为0 int found(int x){ int t; if(f[x]!=x){ t=found(f[x]); dis[x]=(dis[x]+dis[f[x]])%2; //根据儿子与父亲的关系和父亲与爷爷的关系推出儿子与爷爷的关系 f[x]=t; //可以自己枚举一下试一下 } return f[x]; } int main(){ int i,k,t,n,m,a,b,flag,temp,temp1; scanf("%d",&t); for(k=1;k<=t;k++){ flag=1; scanf("%d%d",&n,&m); for(i=1;i<=n;i++){ f[i]=i; dis[i]=0; } //形成的数最多由根节点向下延展两成,因为并查集的原则就是根节点 for(i=1;i<=m;i++){ //相连,因此不会延展超过两成 scanf("%d%d",&a,&b); temp=found(a);temp1=found(b); if(!flag) //如果已经不符合逻辑就不用继续找了 continue; if(temp==temp1){ //当根节点相同时,判断dis数组的值是否相同, if(dis[a]==dis[b]) //这个可以自己画一个树看一下 flag=0; } else{ f[temp1]=temp; //当节点不同时将两个点所属的根节点相连,注意这是候的dis[a]代表的是a与根节点的关系, dis[temp1]=(dis[a]+1-dis[b])%2; //dis[b]代表的是b与根节点的关系,这是因为我们开头的每一次都找了a,b的根节点,在found } //函数中通过回溯更新了dis数组,之后我们将b连到a上,因此a作为b的父节点,b对a的关系一定 } //1,因为a,b是性别不同的,然后通过向量加减求出两个根节点的关系 if(!flag){ printf("Scenario #%d:\n",k); printf("Suspicious bugs found!\n\n"); } else{ printf("Scenario #%d:\n",k); printf("No suspicious bugs found!\n\n"); } } return 0; }