这道题提交了三次吧,每次都wrong,究其原因,前几次都是因为单组输入而不是多组输入,所以while(scanf("%d")!=EOF)这样写是错的。
后来检查发现,查找函数漏了一种情况,补上之后AC。
再来说下思路:
(1):这道题要想用并查集做出来,关键在于懂的用偏移量来表示节点与根节点之间的关系,比如用0表示与根节点同类,用1表示吃根节点,用2表示被根节点吃。
(2):初始化注意点就行。
(3)这道题复杂在要推出节点与节点之间的关系是怎么样的
网上好像都有公式,我是自己算的,然后找规律竟可能的用简洁的代码写出来。。
#include <iostream>
#include <stdio.h>
#define N 800000
using namespace std;
int f[N],c[N],cnt;
int find(int x)
{
if(f[x]==x)return x;
int t=f[x];
f[x]=find(f[x]);
c[x]=(c[x]+c[t])%3;
return f[x];
}
void make(int a,int b,int d)
{
int f1=find(a);
int f2=find(b);
if(f1!=f2)
{
f[f1]=f2;
if(d==2)
{
if(c[a]==0)
c[f1]=(c[b]+1)%3;
else if(c[a]==1)
c[f1]=c[b];
else if(c[a]==2)
c[f1]=(c[b]+2)%3;
}
else if(d==1)
{
if(c[a]==0)
c[f1]=c[b];
else if(c[a]==1)
c[f1]=(c[b]+2)%3;
else if(c[a]==2)
c[f1]=(c[b]+1)%3;
}
}
else
{
if(d==1&&c[a]!=c[b])
cnt++;
else if(d==2)
{
if(c[a]==0&&c[b]!=2)
cnt++;
else if(c[a]==1&&c[b]!=0)
cnt++;
else if(c[a]==2&&c[b]!=1)
cnt++;
}
}
}
int main()
{
int n,m;
int d,x,y;
scanf("%d%d",&n,&m);
cnt=0;
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&d,&x,&y);
if(x>n||y>n)
{
cnt++;
continue;
}
if(d==2&&x==y)
{
cnt++;
continue;
}
make(x,y,d);
}
printf("%d\n",cnt);
return 0;
}