食物链の t j
食物链
首先考虑题目中所说的 3 种矛盾情况中的后两种,都很好判断,关键是如何判断当前的话是与前面的话冲突的。
这里我们先给出两个定理以方便判断一些关系:
一。因为三个种族都有一个且且仅有一个能吃的种族。如果动物 A 能吃 B,动物 C 也能吃 B,那么说明A 和 C 便是同一个种族,否则这个关系就是矛盾的。 二。如果 A 能吃 B,B 能吃 C,那么可以得出 C 能吃 A,也就是如下这个关系:
对于单个点A1,我们可以给它建两个虚点A2,A3,并且假设出这三个点之间的关系,A1吃 A2,A2吃 A3,A3吃A1。同样在假设有一个点B1,它同样也有这些虚点。我们可以使用一个有向图来表示这个关系以方便理解。
当A1可以吃掉B1 时,我们可以发现A1和 B3 成了同类(参考定理 1,同样根据定理 1,我们还可以得出A2和B1是同类,如果是B1吃A1则相反)。
根据定理 2,我们可以得出B1可以吃掉A3,同时它也可以吃掉B2,所以A3 和 B2 也是同类..
如果我们判断两个点是同类,则可以将他们放入同一个并查集中。需要注意的是,虚点只是用来帮助我们判断动物之间的关系的,并没有实际含义。
那么如何判断一句话是矛盾的呢,我们可以分情况讨论。 如果A1 可以吃B1 ,结合图片,我们可以发现A1和B2,依此类推 B1 和A3也不是同类,A1和 B1更不是同类。我们便可以使用并查集,如果上述两者在同一个并查集,便说明它们是矛盾的。
同理如果A1 和B1是同类的话也可以这么考虑。需要注意的是,所以情况都要考虑完,实点和虚点入并查集时情况也要考虑完(不然就是 WA,XD)。
可能有些同学要问为什么要判断两个点在同一个并查集,来判断这句话是不是矛盾的,而不是判断两个点不在同一个并查集,也就是
if(find(A1) == find(B2)) 矛盾
和
if(find(A3) != find(B2)) 矛盾
的区别。
因为我们建立的是虚点,一开始所有的点都在独立的并查集,直接判断便会误判。 可以这么理解,我们在条件不够的情况下,第二种方式是 “猜测”,第一种方式则是 “尽量满足关系,最后不得不判断矛盾”。
关于建立虚点,设当前有 n 个实点,A的两个虚点可以用 A+n和 A+2*n来表示.
#include<bits/stdc++.h>
using namespace std;
int fa[50005*3],n,k,ans;
int find(int x) {
if(fa[x]!=x) return fa[x]=find(fa[x]);
return x;
}
int main() {
cin>>n>>k;
for(int i=1;i<=n*3;i++) fa[i]=i;
for(int i=1,a,x,y;i<=k;i++) {
scanf("%d%d%d",&a,&x,&y);
if(x>n || y>n || (a==2 && x==y)) { ans++; continue; }
if(a==1) {
if((find(x+n) == find(y)) ||(find(x+2*n) == find(y)))
ans++;
else {
fa[find(x+2*n)]=find(y+2*n);
fa[find(x+n)]=find(y+n);
fa[find(x)]=find(y);
}
}
if(a==2) {
if(find(x)==find(y)||find(x+n*2)==find(y)||find(y+n)==find(x)) ans++;
else {
fa[find(x+n)]=find(y);
fa[find(x)]=find(y+2*n);
fa[find(y+n)]=find(x+2*n);
}
}
}
printf("%d",ans);
return 0;
}
本文来自博客园,作者:Doria_tt,转载请注明原文链接:https://www.cnblogs.com/pangtuan666/p/16535240.html