【种类并查集】 poj1182食物链

    xiaoxiao2021-04-15  25

    食物链 Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 70331 Accepted: 20794

    Description

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。  现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。  有人用两种说法对这N个动物所构成的食物链关系进行描述:  第一种说法是"1 X Y",表示X和Y是同类。  第二种说法是"2 X Y",表示X吃Y。  此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。  1) 当前的话与前面的某些真的话冲突,就是假话;  2) 当前的话中X或Y比N大,就是假话;  3) 当前的话表示X吃X,就是假话。  你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 

    Input

    第一行是两个整数N和K,以一个空格分隔。  以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。  若D=1,则表示X和Y是同类。  若D=2,则表示X吃Y。

    Output

    只有一个整数,表示假话的数目。

    Sample Input

    100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5

    Sample Output

    3

    其实也不是原创,而是学习了挑战上的种类并查集的编写方法;

    题意:中文;

    思路:由于N,K很大,所以必须高效的维护动物之间的关系,并快速判断是否产生了矛盾。并查集是维护“属于同一组”的数据结构,但在本体种,并不      只有属于同一类的信息(第一种),还有捕食关系(第二种)的存在。

         对于每只动物i创建三个元素i-A,i-B,i-C,并用这3*N个元素建立并查集。这个并查集维护如下信息:

              *i-x 表示“i属于种类x”;

              *并查集里的每一个组表示组内所有元素代表的情况都同时发生或不发生;

         例如,如果i-A和j-B在同一个组里,就表示如果i属于种类A那么j一定属于种类B,如果j属于种类B,那么i一定属于种类A。比如hdu1829.因此,对于任一条信息,只需要按照下面的进行操作就可以了;

         第一种,x和y属于同类,那么可能都是A,或B,或C类。即合并x-A和y-A、x-B和y-B、x-C和y-C;

         第二种,x吃y的关系,那么可能是x是A类,y是B类、或者x是B类,y是C类、或者x是C类,y是A类;

                即合并x-A和y-B、y-B和y-C、x-C和y-A;

         不过在合并之前,需要先判断合并是否会产生矛盾。例如在第一种信息的情况下,需要检查比如x-A和y-B或者y-C是否在同一组等信息;

         注意:i-A表示i属于种类A;

    起初看到挑战上的程序不太理解,需要手动模拟一下,以后忘记的话,一定手动模拟一下;

    代码:

    #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=50005; int pre[N*3],Rank[N*3]; void init() { for(int i=0;i<N*3;i++) pre[i]=i,Rank[i]=0; } int Find(int x) { if(pre[x]==x) return x; else return pre[x]=Find(pre[x]); } void unite(int x,int y) { x=Find(x); y=Find(y); if(x==y) return ; if(Rank[x]<Rank[y]) pre[x]=y; else { pre[y]=x; if(Rank[x]==Rank[y]) Rank[x]++; } } bool same(int x,int y) { return Find(x)==Find(y); } int main() { int T,x,y,n,k; int ans=0; scanf("%d%d",&n,&k); init(); for(int i=0;i<k;i++) { scanf("%d%d%d",&T,&x,&y); if(x>n||x<=0||y>n||y<=0) { ans++; continue; } if(T==1) { if(same(x,y+N)||same(x,y+2*N)) ans++; else { unite(x,y); unite(x+N,y+N); unite(x+2*N,y+2*N); } } else { if(same(x,y)||same(x,y+2*N)) ans++; else { unite(x,y+N); unite(x+N,y+2*N); unite(x+2*N,y); } } } printf("%d\n",ans); return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-671811.html

    最新回复(0)