您的位置:首页 > 其它

POJ 1182 食物链(加权并查集)

2016-02-24 09:35 369 查看
思路:如果比较两动物之间的关系的话,肯定需要判断一下是否有关系,然后又有什么关系,这个有什么关系的话可以用一个r[]数组表示。

如果两动物有关系k==1&&r[a]!=r[b]一定是假话,k==2,那么r[a]的级别一定是r[b]之前即(r[a]+1)%3==r[b],否则是假话。

如果两者没关系,那么去创建并查集f[]和r[]. 一、要合并首先要查找两者祖先,同时在查找祖先,将经过的节点值回溯给f[x],同时更新r[x],r[x]是在回溯的时候从更早的祖先一点的回退到较晚的祖先,所以我们可以将一个更早祖先的值记录,r[x]=(r[x]+r[t])%3,(t为更早祖先的值)。 二、完成合并,在进行节点的合并时,注意将两种动物合成一到固定的树上,同时更新r[],那么在两棵树进行合并的时候又怎么更新r[]呢?



(这里的x,y,是程序中的a,b;fx,fy是x,y;)

前提我们可以定义三种关系 a b同及为0,a倍b吃为2,b倍a吃为1.

我们可以画出一个正方形

a b

x y 最终我们要x->y所以依次y->bb->aa->xx->y知道他们的关系。a->x,为r[a].

#include<map>
#include<queue>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
#include<algorithm>
#define LL __int64
#define inf 0x3f3f3f3f
const double PI=acos(-1.0);
using namespace std;
int f[1000000],r[1000000];
int fi(int x){
if(x==f[x])
return x;
int t;
t = f[x];
f[x]=fi(f[x]);
r[x] = (r[x] + r[t] )%3;
return f[x];
}

void mer(int a,int b,int k){
int x=fi(a);
int y=fi(b);
f[y]=x;
r[y]=(r[a]-r[b]+k-1+3)%3;
}

int main(){
int n,m,i,j,k,a,b,ans;
scanf("%d%d",&n,&m);
ans=0;
for(i=1;i<=n;++i){
f[i]=i;
r[i]=0;
}
for(i=1;i<=m;++i){
scanf("%d%d%d",&k,&a,&b);
if(a>n||b>n||(k==2&&a==b)){
ans++;continue;
}

if(fi(a)==fi(b)){
if( k==1&&r[a]!=r[b] ) ans++;
else if(k==2&&(r[a]+1)%3!=r[b] ) ans++;
}
else{
mer(a,b,k);
}
}
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 并查集