题意:
给出N条虫子,让a和b交配,
给出M对a和b交配后问,
有没有性别矛盾的虫子,
即和一只虫子和男的交配完之后又和女的交配
题解:
1.压缩路径关系转化,r[x] = (r[x]+r[f[x]])%2,很好理解//r[x]表示x和fx的关系,0同性,1异性
若x和fx为同性(r[x] = 0):
fx和ffx为异性(r[fx] = 1),则x和ffx为异性,x和ffx的关系r[x]更新为0+1=1
fx和ffx为同性(r[fx] = 0),则x和ffx为同性,x和ffx的关系r[x]更新为0+0=0
若x和fx为异性(r[x] = 1):
fx和ffx为异性(r[fx] = 1),则x和ffx为同性,x和ffx的关系r[x]更新为(1+1)%2=0
fx和ffx为同性(r[fx] = 0),则x和ffx为异性,x和ffx的关系r[x]更新为1+0=1
2.并查集联合若父节点相同
if(r[x] == r[y]) mark = true; //x和y性别不同,因为父节点相同,所以x,y和父节点关系相同就是假话
3.并查集联合若父节点不同,这句话为真话,把fy的父节点设置为fx
f[fy] = fx;
r[fy] = (1+r[x]-r[y])%2;
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int f[2010], r[2010];//f数组指向与它交配的bug,初始化自交
//r表示他的父节点与它是同性还是异性,0同性,1异性
bool mark;
int find_head(int x)
{
int fx = x;
if(x != f[x])
{
fx = find_head(f[x]);
r[x] = (r[x]+r[f[x]])%2;
f[x] = fx;
}
return fx;
}
void union_set(int x, int y)
{
int fx = find_head(x);
int fy = find_head(y);
if(fx == fy)//父亲结点相同
{
if(r[x] == r[y]) //x和y性别不同,因为父节点相同,所以x,y和父节点关系相同就是假话
{
mark = true;
}
}
else//父亲结点不同,这句话为真话,把fy的父节点设置为fx
{
f[fy] = fx;
r[fy] = (1+r[x]-r[y])%2;
}
}
int main()
{
int t;
cin>>t;
for(int i = 1; i <= t; i++)
{
int n, m;
mark = false;
scanf("%d%d", &n,&m);
memset(r, 0, sizeof(r));
for(int k = 1; k <= 2010; k++)
{
f[k] = k;
}
for(int j = 1; j <= m; j++)
{
int x, y;
scanf("%d%d", &x,&y);
if(!mark)
{
union_set(x, y);
}
}
cout<<"Scenario #"<<i<<":"<<endl;
if(mark) cout<<"Suspicious bugs found!"<<endl;
else cout<<"No suspicious bugs found!"<<endl;
cout<<endl;
}
}