种类并查集

先来个最水的

poj 2524 Ubiquitous Religions

http://poj.org/problem?id=2524

【题意】给出n个大学生,其中有m对宗教信仰相同的学生,请你估算这n个学生中最多有多少种宗教信仰。

【思路】:  先设 答案为n  每合并一个集合减一就ok了

种类并查集
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <math.h>
 5 using namespace std;
 6 
 7 
 8 int n;
 9 int f[50002];
10 
11 void init()
12 {
13     for(int i=0;i<=n;i++)
14         f[i]=i;
15 
16 }
17 
18 
19 int find(int x)
20 {
21     return f[x]==x?x:f[x]=find(f[x]);
22 }
23 
24 int main()
25 {
26     int i,j,a,b,m,p=1;
27     while(scanf("%d%d",&n,&m))
28     {
29         if(n==0&&m==0)
30             break;
31         init();
32         int ans=n;
33         while(m--)
34         {
35             scanf("%d%d",&a,&b);
36             int aa,bb;
37             aa=find(a);
38             bb=find(b);
39             if(aa!=bb)
40             {
41                 f[aa]=bb;
42                 ans--;
43             }
44         }
45         printf("Case %d: %d\n",p++,ans);
46     }
47 
48     return 0;
49 }
View Code

 

poj 1611  The Suspects

http://poj.org/problem?id=1611

【题意】:N个组的学生,一个学生能同时加入不同的组,同一组的学生会同时感染病毒,现在0号的学生感染了病毒,问一共有多少个人感染病毒。

【思路】 并查集 若是两个 学生在的集合不同(根节点不同)就 合并  只要把一个根节点变成另一个根节点的father  同时新的根节点的 sum值 为两集合之和 就好了  在find x的时候 ,找根节点的同时更新sum[x]的值 (从离根最近的开始)

种类并查集
 1 #include<iostream>
 2 #include<stdio.h>
 3 using namespace std;
 4 
 5 int f[30002],sum[30002],n;
 6 
 7 void init()
 8 {
 9     for(int i=0;i<=n;i++)
10     {
11         sum[i]=1;f[i]=i;
12     }
13 }
14 
15 int find(int x)
16 {
17     if(f[x]==x)
18         return x;
19     f[x]=find(f[x]);
20     sum[x]=sum[f[x]];
21     return f[x];
22 }
23 
24 void lian(int tx,int ty)
25 {
26     f[ty]=tx;
27     sum[tx]+=sum[ty];
28 }
29 
30 int main()
31 {
32     int i,j,m,t,num,a,b;
33     while(~scanf("%d%d",&n,&m))
34     {
35         if(n==0&&m==0)
36             break;
37         init();
38         while(m--)
39         {
40             scanf("%d",&num);
41             scanf("%d",&a);
42             num--;
43             while(num--)
44             {
45                 scanf("%d",&b);
46                 int aa,bb;
47                 aa=find(a);
48                 bb=find(b);
49                 if(aa!=bb)
50                     lian(aa,bb);
51             }
52         }
53         printf("%d\n",sum[find(0)]);
54     }
55 }
View Code

 

poj 1703 

【题意】 有两个帮派,现在告诉你一些互相敌对的点对,然后让你判断某两个点之间的关系

【思路】只要 每个节点 多设一项 kind  表示和根节点的关系是相同还是不同 相同为0 不同为1 输入敌对的 关系时

种类并查集
 1 #include<iostream>
 2 #include<stdio.h>
 3 using namespace std;
 4 
 5 struct node{int kind; int fa;}no[100002];
 6 int n;
 7 
 8 void init()
 9 {
10     for(int i=0;i<=n;i++)
11     {
12         no[i].fa=i; no[i].kind=0;
13     }
14 }
15 
16 int find(int x)
17 {
18     if(no[x].fa==x)
19         return x;
20     int t;
21     t=find(no[x].fa)
22     //  这里执行完 x.fa 的fa和kind都求出来了  fa是 这个集合的根节点 kind是x.fa与根节点的关系 
23     //  而此时 x.fa 和x.kind 都未更新 下面就是 根据 x与x.fa的关系和 x.fa与根节点的关系 推出 x与根节点的关系
24     no[x].kind^=no[no[x].fa].kind;
25     return no[x].fa=t;
26 }
27 
28 int main()
29 {
30     int i,j,m,t,a,b;
31     char c[10];
32     scanf("%d",&t);
33     while(t--)
34     {
35 
36         scanf("%d%d",&n,&m);
37         init();
38         while(m--)
39         {
40             scanf("%s%d%d",c,&a,&b);
41             int aa,bb;
42             aa=find(a);
43             bb=find(b);
44             if(c[0]==D)
45             {
46                 no[aa].fa=bb;
47                 no[aa].kind=no[a].kind^no[b].kind^1;//aa与 bb 的关系 有a与aa的关系 和b与bb的关系推出
48             }
49             else
50             {
51                 if(aa!=bb)
52                    printf("Not sure yet.\n");
53                 else
54                 {
55                     if(no[a].kind==no[b].kind)
56                         printf("In the same gang.\n");
57                     else
58                         printf("In different gangs.\n");
59                 }
60             }
61         }
62     }
63 }
View Code

 

poj 1988 Cube Stacking

http://poj.org/problem?id=1988

【题意】 有n个元素,开始每个元素自己一栈,有两种操作,将含有元素x的栈放在含有y的栈的顶端,合并为一个栈。第二种操作是询问含有x元素下面有多少个元素。

【思路】每个节点除了一项fa 还增加一项d 和一项 sum的表示的是这个节点下面的元素个数 也就是所求。 sum表示的是这个节点所在的集合的节点数

   根节点的d值总是0 。

种类并查集
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 using namespace std;
 5 
 6 struct node{int fa;int sum;int d;} no[30002];
 7 
 8 
 9 
10 int find(int x)
11 {
12     if(no[x].fa==x)
13         return x;
14     int t;
15     t=find(no[x].fa);
16     no[x].d+=no[no[x].fa].d;
17     return no[x].fa=t;
18 }
19 
20 void merge(int tx,int ty)
21 {
22    no[tx].fa=ty;
23    no[tx].d=no[ty].sum;
24    no[ty].sum+=no[tx].sum;
25 
26 }
27 
28 void init()
29 {
30     for(int i = 0;i <= 30000;i++)
31     {
32         no[i].fa = i;
33         no[i].sum=1;
34         no[i].d=0;
35     }
36 }
37 
38 int main()
39 {
40     int a,b,aa,bb,n;
41     char c[10];
42     while(scanf("%d",&n) != EOF)
43     {
44         init();
45 
46         for(int i = 0;i < n;i++)
47         {
48             scanf("%s",c);
49             if(c[0]==M)
50             {
51                 scanf("%d%d",&a,&b);
52                 aa=find(a);
53                 bb=find(b);
54                 if(aa!=bb)
55                     merge(aa,bb);
56                     find(a);
57             }
58             if(c[0]==C)
59             {
60                 scanf("%d",&a);
61                 find(a);
62                 printf("%d\n",no[a].d);
63             }
64         }
65     }
66     return 0;
67 }
View Code

种类并查集

上一篇:mysql 用户管理和权限设置


下一篇:oracle游标小试