码迷,mamicode.com
首页 > 其他好文 > 详细

并查集练习2(带权并查集)

时间:2016-08-13 22:39:07      阅读:422      评论:0      收藏:0      [点我收藏+]

标签:

明天旅游去爬山逛庙玩,今天练一天然后早早睡觉啦~技术分享

poj1703 Find them, Catch them (带权并查集)

技术分享
 1 #include<cstdio>
 2 const int N=1e5+1;
 3 int f[N];
 4 int r[N];//表示与父节点的关系,0同类,1不同类
 5 int n;
 6 void init(){
 7     for(int i=1;i<=n;++i){
 8         f[i]=i; r[i]=0;
 9     }
10 }
11 int fin(int x){
12     int t;
13     if(x==f[x])return x;
14     t=f[x];//记录父节点
15     f[x]=fin(f[x]);
16     r[x]^=r[t];//类别偏移,或r[x]=(r[x]+r[t])%2
17     return f[x];
18 }
19 void uni(int x,int y){
20     int fx=fin(x);
21     int fy=fin(y);
22     f[fx]=fy;
23     r[fx]=~(r[x]^r[y]);//类别偏移,或r[fx]=(-r[x]+1+r[y]+2)%2
24                         //  关系:fx与fy= fx与x+ x与y + y与fy
25 }
26 int main(){
27     int t,m,a,b;
28     char s[3];
29     scanf("%d",&t);
30     while(t--){
31         scanf("%d%d",&n,&m);
32         init();
33         while(m--){
34             scanf("%s%d%d",s,&a,&b);
35             if(s[0]==D) uni(a,b);
36             else{
37                 if(fin(a)!=fin(b)){
38                     if(n==2) printf("In different gangs.\n");
39                     else printf("Not sure yet.\n");
40                 }
41                 else{
42                     if(r[a]==r[b])
43                         printf("In the same gang.\n");
44                     else printf("In different gangs.\n");
45                 }
46             }
47         }
48     }
49     return 0;
50 }
View Code

 

poj2492 A Bug‘s Life(带权并查集):与上题差不多嗷。

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int N=2001;
 5 int f[N];
 6 int r[N];
 7 int n;
 8 void init(){
 9     for(int i=1;i<=n;++i){
10         f[i]=i; r[i]=0;
11     }
12 }
13 int fin(int x){
14     int t;
15     if(x==f[x])return x;
16     t=f[x];
17     f[x]=fin(f[x]);
18     r[x]^=r[t];
19     return f[x];
20 }
21 void uni(int x,int y){
22     int fx=fin(x);
23     int fy=fin(y);
24     f[fx]=fy;
25     r[fx]=~(r[x]^r[y]);
26 }
27 int main(){
28     int t,m,a,b,k=1,f;
29     scanf("%d",&t);
30     while(t--){
31         scanf("%d%d",&n,&m);
32         init();
33         f=1;
34         while(m--){
35             scanf("%d%d",&a,&b);
36             if(f&&fin(a)==fin(b)&&r[a]==r[b])f=0;
37             else uni(a,b);
38         }
39         printf("Scenario #%d:\n%s\n\n",k++,f?"No suspicious bugs found!":"Suspicious bugs found!");
40     }
41     return 0;
42 }
View Code

 

poj1988 Cube Stacking (带权并查集):栈顶方块为父节点,r[i]为i到父节点的距离,num[fin(i)]表示包含i的栈的大小,相减即可。

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int N=30001;
 5 int f[N],r[N],num[N];
 6 int n;
 7 void init(){
 8     for(int i=1;i<N;++i){
 9         f[i]=i; r[i]=0; num[i]=1;
10     }
11 }
12 int fin(int x){
13     int t;
14     if(x!=f[x]){
15         t=f[x];
16         f[x]=fin(f[x]);
17         r[x]+=r[t];
18     }
19     return f[x];
20 }
21 void uni(int x,int y){
22     int fx=fin(x);
23     int fy=fin(y);
24     if(fx!=fy){
25         f[fy]=fx;
26         r[fy]=num[fx];
27         num[fx]+=num[fy];
28     }
29 }
30 int main(){
31     int m,a,b;
32     char s[3];
33     scanf("%d",&m);
34     init();
35     while(m--){
36         scanf("%s",s);
37         if(s[0]==M){
38             scanf("%d%d",&a,&b);
39             uni(a,b);
40         }
41         else{
42             scanf("%d",&a);
43             printf("%d\n",num[fin(a)]-r[a]-1);
44         }
45     }
46     return 0;
47 }
View Code

 

hdu3047 Zjnu Stadium(带权并查集)

技术分享
 1 #include<cstdio>
 2 #include<map>
 3 using namespace std;
 4 const int N=50001;
 5 int f[N];
 6 int r[N];
 7 int n,cnt;
 8 void init(){
 9     for(int i=1;i<=n;++i){
10         f[i]=i; r[i]=0;
11     }
12 }
13 int fin(int x){
14     int t;
15     if(x!=f[x]){
16         t=f[x];
17         f[x]=fin(f[x]);
18         r[x]+=r[t];
19     }
20     return f[x];
21 }
22 void uni(int x,int y,int d){
23     int fx=fin(x);
24     int fy=fin(y);
25     if(fx==fy){
26         if(r[y]-r[x]!=d) cnt++;
27     }
28     else{
29         f[fy]=fx;
30         r[fy]=-r[y]+r[x]+d;
31     }
32 }
33 int main(){
34     int m,d,i,a,b;
35     while(scanf("%d%d",&n,&m)==2){
36         cnt=0;
37         init();
38         while(m--){
39             scanf("%d%d%d",&a,&b,&d);
40             uni(a,b,d);
41         }
42         printf("%d\n",cnt);
43     }
44     return 0;
45 }
View Code

 

hdu3038 How Many Answers Are Wrong(带权并查集)与上题差不多耶。

技术分享
 1 #include<cstdio>
 2 #include<map>
 3 using namespace std;
 4 const int N=200001;
 5 int f[N];
 6 int r[N];//表示与父节点之间的和
 7 int n,cnt;
 8 void init(){
 9     for(int i=0;i<=n;++i){
10         f[i]=i; r[i]=0;
11     }
12 }
13 int fin(int x){
14     int t;
15     if(x!=f[x]){
16         t=f[x];
17         f[x]=fin(f[x]);
18         r[x]+=r[t];
19     }
20     return f[x];
21 }
22 void uni(int x,int y,int d){
23     int fx=fin(x);
24     int fy=fin(y);
25     if(fx==fy){
26         if(r[y]-r[x]!=d) cnt++;
27     }
28     else{
29         f[fy]=fx;
30         r[fy]=-r[y]+r[x]+d;
31     }
32 }
33 int main(){
34     int m,d,i,a,b;
35     while(scanf("%d%d",&n,&m)==2){
36         cnt=0;
37         init();
38         while(m--){
39             scanf("%d%d%d",&a,&b,&d);
40             uni(a-1,b,d);
41         }
42         printf("%d\n",cnt);
43     }
44     return 0;
45 }
View Code

 

poj1182 食物链 (带权并查集)经典吖orz.

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int N=50001;
 5 int f[N];
 6 int r[N];//表示与父节点的关系,0表示同类,1表示被吃,2表示吃父节点
 7 int n,ans;
 8 void init(){
 9     for(int i=1;i<=n;++i){
10         f[i]=i; r[i]=0;
11     }
12 }
13 int fin(int x){
14     int t;
15     if(x!=f[x]){
16         t=f[x];
17         f[x]=fin(f[x]);
18         r[x]=(r[x]+r[t])%3;
19     }
20     return f[x];
21 }
22 void uni(int x,int y,int d){
23     int fx=fin(x);
24     int fy=fin(y);
25     if(fx==fy){
26         if((r[x]-r[y]+3)%3!=d) ans++;
27     }
28     else{
29         f[fx]=fy;
30         r[fx]=(-r[x]+d+r[y]+3)%3;
31     }
32 }
33 int main(){
34     int m,a,b,d;
35     scanf("%d%d",&n,&m);
36     init();
37     ans=0;
38     while(m--){
39         scanf("%d%d%d",&d,&a,&b);
40         if(a>n||b>n||(d==2&&a==b))ans++;//假话:a或b都大于n,或a吃a
41         else  uni(a,b,d-1);
42     }
43     printf("%d\n",ans);
44     return 0;
45 }
View Code

 

poj2912 Rochambeau(带权并查集,枚举)石头剪刀布的游戏,并查集部分和上题食物链很像哦。枚举每个小孩为裁判时的情况,再并查集判断。

技术分享
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=501;
 6 const int M=2001;
 7 int f[N],r[N];
 8 int n;
 9 void init(){
10     for(int i=0;i<n;++i){
11         f[i]=i; r[i]=0;
12     }
13 }
14 int fin(int x){
15     int t;
16     if(x!=f[x]){
17         t=f[x];
18         f[x]=fin(f[x]);
19         r[x]=(r[x]+r[t])%3;
20     }
21     return f[x];
22 }
23 int uni(int x,int y,int d){
24     int fx=fin(x);
25     int fy=fin(y);
26     if(fx==fy){
27         if((r[x]-r[y]+3)%3!=d) return 0;
28         return 1;
29     }
30     else{
31         f[fx]=fy;
32         r[fx]=(-r[x]+d+r[y]+3)%3;
33         return 1;
34     }
35 }
36 int main(){
37     int m,d,i,j,a[M],b[M],flag,cnt,id,ans,D[M];
38     char s[M],c;
39     while(scanf("%d%d",&n,&m)==2){
40         for(i=1;i<=m;++i){
41             scanf("%d",&a[i]);
42             while(scanf("%c",&s[i]),s[i]== );
43             scanf("%d",&b[i]);
44             if(s[i]===)D[i]=0;
45             else if(s[i]==>)D[i]=1;
46             else D[i]=2;
47         }
48         cnt=ans=id=0;
49         for(i=0;i<n;++i){//枚举每个裁判
50             init();
51             flag=0;
52             for(j=1;j<=m;++j){
53                 if(a[j]!=i&&b[j]!=i){
54                     if(!uni(a[j],b[j],D[j])){
55                         flag=1;
56                         if(j>ans) ans=j;//取最大的矛盾轮数
57                         break;
58                     }
59                 }
60             }
61             if(!flag){ id=i; cnt++;}
62         }
63         if(cnt==0) puts("Impossible");
64         else if(cnt==1)
65             printf("Player %d can be determined to be the judge after %d lines\n",id,ans);
66         else  puts("Can not determine");
67     }
68     return 0;
69 }
View Code

 

poj1733 Parity game(带权并查集,离散化)

题意:有一个已知长度的01串,给出多个区间[l,r],并知道区间中1的个数是奇数还是偶数,问前几个区间互不矛盾。

离散化hash暂时还不会,先用map映射处理大数据问题吧。。

技术分享
 1 #include<cstdio>
 2 #include<map>
 3 using namespace std;
 4 const int N=5001;
 5 int f[N];
 6 int r[N];//表示到父节点的1的个数的奇偶性,0表示偶数个1,1表示奇数个1
 7 int n;
 8 void init(){
 9     for(int i=0;i<N;++i){
10         f[i]=i; r[i]=0;
11     }
12 }
13 int fin(int x){
14     int t;
15     if(x!=f[x]){
16         t=f[x];
17         f[x]=fin(f[x]);
18         r[x]=(r[x]+r[t])%2;
19     }
20     return f[x];
21 }
22 int uni(int x,int y,int d){
23     int fx=fin(x);
24     int fy=fin(y);
25     if(fx==fy){
26         if((r[x]-r[y]+2)%2!=d) return 0;
27         return 1;
28     }
29     f[fx]=fy;
30     r[fx]=(-r[x]+d+r[y]+2)%2;
31     return 1;
32 }
33 int main(){
34     int m,d,i,k,a,b,flag,ans;
35     char s[10];
36     while(scanf("%d%d",&n,&m)==2){
37         init();
38         map<int,int>p;
39         flag=1;
40         k=0;
41         ans=m;
42         for(i=0;i<m;++i){
43             scanf("%d%d%s",&a,&b,s);
44             if(!flag)continue;
45             d=(s[0]==e?0:1);
46             b++;
47             if(p.find(a)==p.end()) p[a]=k++;
48             if(p.find(b)==p.end()) p[b]=k++;
49             if(!uni(p[a],p[b],d)){
50                 flag=0;
51                 ans=i;
52             }
53         }
54         printf("%d\n",ans);
55     }
56     return 0;
57 }
View Code

 

写完随笔怎么突然有种很萌比的感觉。。。下个月的今天再复习一下好啦。。

并查集练习2(带权并查集)

标签:

原文地址:http://www.cnblogs.com/GraceSkyer/p/5769014.html

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!