施法中………………………………………………………………….
……………………………………………………………………………
peng! 一道传送门:
http://poj.org/problem?id=2492
这题是类似于POJ1182食物链同样类型的,加权并查集。
可以先做这道题,之后在做1182—http://poj.org/problem?id=1182
先说说这道题,比较变态吧,研究虫子是不是同性恋。
我们在并查集的基础上加一个 r【】 代表当前点与其父节点的关系,我们假设0代表同性,1代表异性。
我们在找祖宗的时候我们可以想到每次更换父节点,r[]都会有所改变。
//我们用 int t代表当前点 x 的父节点。那么当我们更换父节点是,r[x]的值会改变。
//我们可以看到
x x的爹 x与x他爹的爹(也就是x的爷爷)
0 1 1
1 0 1
1 1 1
0 0 0
这个大家最好自己 推倒 X我是污妖王X 一遍(当然你可以推倒好多次)
那么r[x]=(r[x]+r[t])%2
之后find_father的部分说完了,该联合的部分了
两个点联合,他们的关系应该怎么写呢?
我们假设 unite(int x,int y)
xx为x的祖宗 yy为y的祖宗
当祖宗不同时,f[yy]=xx;sex[yy]=(sex[x]+sex[y]+1)%2;
这个公式是怎么推来的呢?
x对根节点 xx 为1 xx对x也为1 同理可得yy与y 之后+1
是因为 x与y 结合 表明x 与 y 恋爱 更改一下关系变好了,当然可以写成
sex[yy]= (sex[x]-sex[x]+1)%2
好了附上代码:
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define N 500100
using namespace std;
int f[N],sex[N];
int n,m;
void init(int n)
{
for(int i=0;i<=n;i++)
{
f[i]=i;
sex[i]=0;
}
}
int find_father(int x)
{
if(x==f[x])
return x;
int t=f[x];
f[x]=find_father(f[x]);
sex[x]=(sex[x]+sex[t])%2;
return f[x];
}
void unin(int x,int y)
{
int xx=find_father(x);
int yy=find_father(y);
if(xx!=yy)
{
f[yy]=xx; // y-y father is---> xx;
sex[yy]=(sex[y]+sex[x]+1)%2; // x 喜欢 y
}
}
int main()
{
int t,times=1,x,y;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
init(n);
int flag=0;
for(int i=0;i<m;i++)
{
scanf("%d %d",&x,&y);
if(find_father(x)==find_father(y))
{
if(sex[x]!=(sex[y]+1)%2)
{
flag=1;
}
}
else
unin(x,y);
}
printf("Scenario #%d:\n",times++);
if(flag)
printf("Suspicious bugs found!\n\n");
else printf("No suspicious bugs found!\n\n");
}
return 0;
}
写的不好,请多指导。谢谢大家了。