poj1703(各种姿势)

ygeloutingyu ygeloutingyu     2022-08-10     232

关键词:

题目链接:http://poj.org/problem?id=1703

 

题意:有n个人分别属于两个团伙,接下来m组形如 ch, x, y的数据,ch为“D"表示 x, y属于不同的团伙,ch为"A"表示询问x,y书否属于同一个团伙;

 

解法1:我们可以用jion(x, y)属于同一个团伙,jion(x+n, y)表示x属于第二个团伙,y属于第一个团伙,jion(x, y+n)表示x属于第一个团伙,y属于第二个团伙;

那么对于每组不同团伙的x, y我们只需要jion(x+n, y) ,jion(x, y+n)即可;查询时判断x,y或者x+n, y+n根节点是否相同即可,因为集合关系jion表示属于同一团伙,根节点相同则属于相同团伙,若x, y+n,或者x+n, y根节点相同则属于不同团伙,其余情况即为不能确定;

 

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define MAXN (100000+10)  //***MAXN后面做下标时MAXN*2,要加括号,不然会越界!!run time error!!!
 5 using namespace std;
 6 
 7 int pre[MAXN*2], rank[MAXN*2]; //***rank用来区分树的高度,但其不存储树的具体高度
 8 
 9 int find(int x){    
10     int r = x;
11     while(pre[r]!=r){
12         r = pre[r];
13     }
14     int i = x;      //****路径压缩
15     while(pre[i]!=r){
16         int gg = pre[i];
17         pre[i] = r;
18         i = gg;
19     }
20     return r;
21 }
22 
23 void jion(int x, int y){
24     int xx = find(x);
25     int yy = find(y);
26     if(rank[xx]>rank[yy]){   //***启发式合并,就是把矮的树合并到高的树地下,把合并时间从0(n)降到o(logn)
27         pre[yy] = xx;
28     }else{
29         pre[xx] = yy;
30         if(rank[xx] == rank[yy]){ //**若树的标记高度一样,那么给合并后作为父亲的树rank+1,以区分树的高度
31             rank[xx]++;
32         }
33     }
34 }
35 
36 int main(void){
37     int t;
38     scanf("%d", &t);
39     while(t--){
40         int n, m;
41         scanf("%d%d", &n, &m);
42         for(int i=1; i<=2*n; i++){
43             pre[i] = i;
44             rank[i] = 0;
45         }
46         while(m--){
47             char ch[2];
48             int x, y;
49             scanf("%s%d%d", ch, &x, &y);
50             if(ch[0]==D){
51                 jion(x, y+n);
52                 jion(x+n, y);
53             }else{
54                 if(find(y+n)==find(x)||find(x+n)==find(y)){
55                     printf("In different gangs.
");
56                 }else if(find(x)==find(y)||find(x+n)==find(y+n)){
57                     printf("In the same gang.
");
58                 }else{
59                     printf("Not sure yet.
");
60                 }
61             }
62         }
63     }
64     return 0;
65 }

 

方法2:用vis数组标记不同的集合,如:vis[x]=y,表示与x不同集合的点y;

用并查集合并属于同一类的点集;

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #define MAXN 100010
 4 using namespace std;
 5 
 6 int pre[MAXN], vis[MAXN], rank[MAXN]; //***vis标记不同集合的编号,rank区分树高
 7 //***vis[x]=y,表示记录x与y不同集合,相当于无向图,所以需双向标记
 8 
 9 /*int find(int x){  //**400+ms
10     int r = x;
11     while(pre[r]!=r){
12         r = pre[r];
13     }
14     int i = x;
15     while(i!=r){
16         int gg = pre[i];
17         pre[i] = r;
18         i = gg;
19     }
20     return r;
21 }*/
22 
23 int find(int x){ //**306ms (再加启发式合并=282ms)
24     return pre[x]==x ? x : pre[x] = find(pre[x]);
25 }
26 
27 void jion(int x, int y){
28     int xx = find(x);
29     int yy = find(y);
30     if(rank[xx] > rank[yy]){
31         pre[yy] = xx;
32     }else{
33         pre[xx] = yy;
34         if(rank[xx] == rank[yy]){
35             rank[yy]++;
36         }
37     }
38 }
39 
40 int main(void){
41     int t;
42     scanf("%d", &t);
43     while(t--){
44         int n, m;
45         scanf("%d%d", &n, &m);
46         for(int i=1; i<=n; i++){
47             pre[i] = i;
48             vis[i] = 0;
49             rank[i] = 0;
50         }
51         while(m--){
52             char ch[2];
53             int x, y;
54             scanf("%s%d%d", ch, &x, &y);
55             if(ch[0]==D){
56                 if(vis[x]==0 && vis[y]==0){  //**x, y都没出现过
57                     vis[x] = y;
58                     vis[y] = x;
59                 }else if(vis[x]==0){ //**x没出现过
60                     vis[x] = y;
61                     jion(x, vis[y]);
62                 }else if(vis[y]==0){ //**y没出现过
63                     vis[y] = x;
64                     jion(y, vis[x]);
65                 }else{               //**都出现过
66                     jion(x, vis[y]);
67                     jion(y, vis[x]);
68                 }
69             }else{
70                 if(find(x)==find(y)){
71                     printf("In the same gang.
");
72                 }else if(find(x)==find(vis[y])){
73                     printf("In different gangs.
");
74                 }else{
75                     printf("Not sure yet.
");
76                 }
77             }
78         }
79     }
80     return 0;
81 }

 

方法3:

种类并查集,先区分能不能辨别的情况,然后只要考虑同和不同两种情况,可以用rank数组记录当前节点x与其根节点是否相同的信息,1表相同,0表不同;

 

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #define MAXN 100010
 4 using namespace std;
 5 
 6 int pre[MAXN], rank[MAXN]; //**rank储存x与x的根节点是否相同的信息,1表相同,0表不同
 7 
 8 int find(int x){
 9     if(x==pre[x]){
10         return pre[x];
11     }
12     int xx = pre[x];
13     pre[x] = find(pre[x]);
14     rank[x] = (rank[x] + rank[xx])&1; //**压缩路径,x的根节点改变了,rank[x]也要改变
15     return pre[x];
16 }
17 
18 void jion(int x, int y){
19     int xx = find(x);
20     int yy = find(y);
21     if(xx!=yy){
22         pre[yy] = xx;
23         rank[yy] = (rank[x] + rank[y] + 1)&1; //**合并只需改变yy之前的rank值
24     }
25 }
26 
27 int main(void){
28     int t;
29     scanf("%d", &t);
30     while(t--){
31         int n, m;
32         scanf("%d%d", &n, &m);
33         for(int i=1; i<=n; i++){
34             pre[i] = i;
35             rank[i] = 0;
36         }
37         while(m--){
38             char ch[2];
39             int x, y;
40             scanf("%s%d%d", ch, &x, &y);
41             if(ch[0]==D){
42                 jion(x, y);
43             }else{
44                 if(find(x)==find(y)){
45                     if(rank[x]==rank[y]){
46                         printf("In the same gang.
");
47                     }else{
48                         printf("In different gangs.
");
49                     }
50                 }else{
51                     printf("Not sure yet.
");
52                 }
53             }
54         }
55     }
56     return 0;
57 }

 

poj1703findthem,catchthem

Findthem,CatchthemTimeLimit:1000MS MemoryLimit:10000KTotalSubmissions:47222 Accepted:14543DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactionstorootuptheTWOgangsint 查看详情

poj1703findthem,catchthem

 TimeLimit: 1000MS MemoryLimit: 10000KTotalSubmissions: 41913 Accepted: 12879DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactionstorootupth 查看详情

poj-1703-findthem,catchthem

Findthem,CatchthemTimeLimit: 1000MS MemoryLimit: 10000KTotalSubmissions: 41928 Accepted: 12886DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactio 查看详情

poj1703findthem,catchthem

Findthem,CatchthemTimeLimit: 1000MS MemoryLimit: 10000KTotalSubmissions: 46119 Accepted: 14193DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactio 查看详情

(poj1703)findthem,catchthem

Findthem,CatchthemTimeLimit: 1000MS MemoryLimit: 10000KTotalSubmissions: 46763 Accepted: 14398DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactio 查看详情

poj1703

Findthem,CatchthemTimeLimit:1000MS MemoryLimit:10000KTotalSubmissions:62172 Accepted:18837DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactionstorootuptheTWOgangsinthecity,GangDragonandGangSnake.However,thepolicefirstneedstoidentifywhichgangacriminalbelongsto.Thepr... 查看详情

[并查集]poj1703findthem,catchthem

Findthem,CatchthemTimeLimit: 1000MS MemoryLimit: 10000KTotalSubmissions: 43132 Accepted: 13257DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactio 查看详情

poj1703-并查集(代码片段)

                  Findthem,CatchthemTimeLimit: 1000MS MemoryLimit: 10000KTotalSubmissions:  查看详情

poj1703findthem,catchthem

http://poj.org/problem?id=1703应该是书上例题(食物链POJ1822)的简单版这里同样用书上很巧妙的思路如何表达在集合A和集合B中并不是让i.set=A 类似于这样活着P[i]=A而是将这个变成一个隐形条件并且不用再关心i到底是在A集合还是在B集... 查看详情

poj1703--findthem,catchthem(种类并查集)

TimeLimit:1000MSMemoryLimit:10000KTotalSubmissions:32909Accepted:10158DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactionstorootuptheTWOgangsinthecity,GangDragonandGangSnake. 查看详情

poj1703findthem,catchthem

                                 &n 查看详情

poj1703findthem,catchthem(带权并查集)

题目链接http://poj.org/problem?id=1703题意有两个帮派:龙帮和蛇帮,两个帮派共有n个人(编号1~n),输入m组数据,每组数据为D[a][b]或A[a][b],D[a][b]表示a,b属于不同的帮派,A[a][b]则让我们判断a,b是否属于一个帮派,根据判断的结... 查看详情

poj1703findthem,catchthem(带权并查集)

传送门Findthem,CatchthemTimeLimit: 1000MS MemoryLimit: 10000KTotalSubmissions: 42463 Accepted: 13065DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchac 查看详情

poj-1703-findthem,catchthem(并查集分类)(代码片段)

DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactionstorootuptheTWOgangsinthecity,GangDragonandGangSnake.However,thepolicefirstneedstoidentifywhichgangacriminalbelongsto.Thepr 查看详情

poj1703-findthem,catchthem(加权并查集)题解

...链接放在正文醒目位置。题目链接:http://poj.org/problem?id=1703题目大意:N个人分属两个黑帮。给出M条信息。(M,N<=10^5)Dxy表示已知x和y不在同一个黑帮中。Axy表示询问x和y是否在一个黑帮中。如果是,输出Indifferentgangs.如果不是... 查看详情

[poj1703]findthem,catchthem(并查集)

传送门 1.开两个并查集f[x]表示x的同类f[x+n]表示x的敌人 ——代码1#include<cstdio>2#include<iostream>3#defineN20000145intT,n,m;6intf[N];78inlineintread()9{10intx=0,f=1;11charch=getchar();12for 查看详情

poj1703findthem,catchthem(并查集)(代码片段)

https://vjudge.net/problem/POJ-17039ms多,卡着时间过了。上次一道并查集也是这样,总觉得要学一波并查集的优化。。续:好像是可以只做一层存放敌人即可。1#include<iostream>2#include<cstdio>3#include<queue>4#include<cstring>5#incl... 查看详情

poj1703findthem,catchthem(确定元素归属集合的并查集)(代码片段)

Findthem,CatchthemTimeLimit:1000MS MemoryLimit:10000KTotalSubmissions:52925 Accepted:16209DescriptionThepoliceofficeinTaduCitydecidestosayendstothechaos,aslaunchactionstorootuptheTWOgangsint 查看详情