虫子的那个题可能比这个食物链简单,但我是先看会了食物链,回头才看懂了虫子
POJ 1182/食物链//扩展并查集
题目链接 acwing题库链接
对于扩展并查集,理解可能还不够透彻,现在记录目前的理解状况
因为这个能形成一个环,能用扩展并查集来写
我们开一个三倍的长度,其中 1-m 表示 i 的同伴1是 f 【i】;在m - 2*m 区间里, 他的意思是 i 能吃 f【i】(食物);在2*m - 3*m 的区间里,意思代表 i 的天敌是 f 【i】。
当 a 能吃 b 是,因为这是一个环,所以我们能够得到
a 的朋友是 b 天敌 的朋友(敌人的敌人是朋友//环的原因)
a 的食物是 b 的同类
a 的天敌是 b 的食物
上面三个情况代码表示为
f[find(a)]=find(2*m+b);
f[find(a+m)]=find(b);
f[find(a+2*m)]=find(m+b);
这个理解时,我们在来判断说谎的可能情况
一, a b 大于N
二, D==1,如果存在 a 的食物时 b,或者 b 的食物时 a
三, D==2,如果 存在 a 的同伴时 b ,或者 b 的食物时 a
说的话为假。
#include<iostream>
using namespace std;
const int N=1e6+5;
int f[N],ans=0;
int find(int x)
{
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
int main()
{
int m,n;
scanf("%d%d",&m,&n);
for(int i=1;i<=3*m;i++)
f[i]=i;
for(int i=1;i<=n;i++)
{
int o,a,b;
scanf("%d%d%d",&o,&a,&b);
if(a<=0||b<=0||a>m||b>m)
{
ans++;
}
else
{
if(o==1)
{
if(find(a)==find(b+m)||find(a+m)==find(b))
{
ans++;
continue;
}
f[find(a)]=find(b);
f[find(a+m)]=find(b+m);
f[find(a+2*m)]=find(b+2*m);
}
else
{
if(find(a)==find(b)||find(b+m)==find(a))
{
ans++;
continue;
}
f[find(a)]=find(2*m+b);
f[find(a+m)]=find(b);
f[find(a+2*m)]=find(m+b);
}
}
}
printf("%d\n",ans);
}
poj 2492/虫子//
这个题目只需要维护敌对关系即可,同伴关系的维护不好或者不可能取维护。
#include<iostream>
using namespace std;
const int N=4040;
int f[N];
int find(int x)
{
if(x!=f[x])
f[x]=find(f[x]);
return f[x];
}
int main()
{
int T;
cin>>T;
for(int TT=1;TT<=T;TT++)
{
int m,n;
cin>>m>>n;
for(int i=1;i<=2*m;i++) f[i]=i;
int t=0;
for(int i=1;i<=n;i++)
{
int a,b;
cin>>a>>b;
int c=find(a);
int d=find(b);
if(t) continue;
if(c==d) t=1;
else
{
f[find(a+m)]=find(b);
f[find(b+m)]=find(a);
}
}
cout<<"Scenario #"<<TT<<":\n";
if(t) cout<<"Suspicious bugs found!\n\n";
else cout<<"No suspicious bugs found!\n\n";
}
return 0;
}