【并查集】食物链(带权并查集)

问题 A: 食物链

时间限制: 1 Sec  内存限制: 128 MB

题目描述

        动物王国中有三类动物  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),输出假话的总数。

输入

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

输出

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

样例输入

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

样例输出

3

提示

 

100 7

1 101 1    假话 

2 1 2      真话 

2 2 3      真话 

2 3 3      假话 

1 1 3      假话 

2 3 1      真话 

1 5 5      真话 
 
 
【分析】
 1.如果a吃b,b吃c,c吃d,那么a和d为同类;
 2.如果a吃b,c也吃b,那么a和c也为同类;
 显而易见,这道题目就可以用“并查集”来完成。
 
 如果x吃y则有一条x指向y边权为1的边,如果x被y吃则有一条x指向y边权为2的边;
 处理:如果x y在一个集合则描述判断是否合法,如果x y不在一个集合则合并两个集合;
 
 1 #include<iostream> 
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 int p[50005],f[50005];  //p mean the father of i;
 7                         //f mean the length of i to its father;
 8 int father(int x)       //find its father
 9 {
10     if (x!=p[x]) 
11     {
12         int temp=p[x];
13         p[x]=father(p[x]);
14         f[x]=(f[x]+f[temp])%3;
15     }
16     return p[x];
17 }
18 int main()
19 {
20     int n,k,d,x,y,count=0;
21     scanf("%d%d",&n,&k);
22     for (int i=1;i<=n;i++)
23     {
24         p[i]=i; f[i]=0;
25     }   //firstly
26     for (int i=1;i<=k;i++)
27     {
28         scanf("%d%d%d",&d,&x,&y);
29         if ((d==2&&x==y)||(x>n||y>n))  
30          {
31              count++;
32              continue;
33          }
34         if (d==1)
35         {
36             if (father(x)==father(y))
37              {
38                  if (f[x]!=f[y]) count++;
39              }
40              else 
41              {
42                  f[p[x]]=(f[y]-f[x]+3)%3;
43                  p[p[x]]=p[y];
44              }
45         }
46         if (d==2)
47         {
48             if (father(x)==father(y))
49              {
50                  if (f[x]!=((f[y]+1)%3)) count++;
51              }
52           else
53             {
54                f[p[x]]=(f[y]-f[x]+4)%3;
55                p[p[x]]=p[y];
56              }
57         }
58     }
59    printf("%d",count);
60     
61 }

 

 

一段时间后再回来研究这道题,并且要学习一下带权并查集

(之前还有一个并查集专题,也可以再回顾一下啊)

带权并查集

带权值的并查集只不过是在并查集中加入了一个value[ ]数组
value[ ]可以记录很多种东西,不一定是类似距离这种东西,也可以是相对于根节点的状态
加入了权值,函数应该有一些改变
function find(x:longint):longint;
var tmp:longint;
begin
    if father[x]=x then exit(x);
    tmp:=father[x];
    father[x]:=find(father[x]);
    //下面一句可以随意改
    value[x]:=value[tmp]+1;
    exit(father[x]);
end;

-知识点完-

 

 

接下来上食物链题解(简单粗暴的题解)

 

var
n,m,i,ans:longint;
father,size:array[0..50000]of longint;
function find(x:longint):longint;
var t:longint;
begin
    if father[x]=x then exit(x)
        else
            begin
                t:=father[x];
                father[x]:=find(father[x]);            //路径压缩
                size[x]:=(size[x]+size[t]) mod 3;   
                //根据找规律可得,各种情况两两结合可得size
                exit(father[x]);
            end;
end;
function judge:boolean;
var kind,x,y,fx,fy:longint;
begin
    //以下的各种判定可用向量的规律判断得
    readln(kind,x,y);
    if (x>n)or(y>n) then exit(false);
    if (kind=2)and(x=y) then exit(false);
    fx:=find(x);     fy:=find(y);
    if fx=fy then    
        begin
            if (size[y]-size[x]+3) mod 3<>(kind-1) then exit(false) 
                else exit(true);
        end
    else
        begin
            father[fy]:=fx;
            size[fy]:=(size[x]-size[y]+kind-1+3) mod 3;
            exit(true);
        end;
end;
begin
    readln(n,m);
    for i:=1 to n do
        begin
            father[i]:=i;
            size[i]:=0;
        end;
    for i:=1 to m do 
        if judge=false then ans:=ans+1;
    writeln(ans);
end.

 

 

posted @ 2017-07-23 21:35  Hathawaxy  阅读(292)  评论(0编辑  收藏  举报