poj 并查集
http://poj.org/problem?id=1611
水题
题意:就是找一共有多少个人感染了,0是感染学生的编号。
#include <stdio.h> #include <string.h> #define maxn 30005 int m,n; int belg[ maxn ]; int Find(int x) { int _x=x,_b; while( _x != belg[ _x ] ) _x = belg[ _x ]; while( x != belg[ x ] ) { _b = belg[ x ]; belg[ x ] = _x; x = _b; } return _x; } void unio(int x,int y) { int root1 = Find(x); int root2 = Find(y); if( root1 != root2 ) belg[root2] = root1; } int main() { // freopen("in.txt","r",stdin); int a,b,c,ans; while(scanf("%d%d",&m,&n),m||n) { for( int i = 0 ; i <= m ; i++ ) belg[ i ] = i; for( int i = 0 ; i < n ; i++ ) { scanf("%d%d",&a,&b); for( int j = 0 ; j < a-1 ; j++ ) { scanf("%d",&c); unio(b,c); } } ans = 0; a = Find(0); for(int i = 0 ; i <= m ; i++ ) if(Find(i)==a) ans++; printf("%d\n",ans); } return 0; }
poj 2492
http://poj.org/problem?id=2492
题意:给出m组关系,要你判断这里面有没有同性恋。
这是并查集的一个高级用法,但是我是第一次用并查集的高级用法,现在也还不是很理解这是为什么,什么意思。还得好好的模拟,想一想,感觉身体被掏空
1 #include <stdio.h> 2 #include <string.h> 3 #define maxn 5005 4 5 6 int belg[ maxn ]; 7 bool kind[ maxn ],sign; 8 9 int Find(int x, bool &s) 10 { 11 int _x, h = x; 12 bool s1, s2; 13 14 while ( belg[h]!=h ) 15 { 16 s = s^kind[h]; 17 18 //这里的目的是看s也就是当前的x是不是与他的祖父是相同性别的。 19 20 h = belg[h]; 21 } 22 23 s1 = s; 24 while ( belg[x]!=x ) 25 { 26 _x = belg[x]; 27 belg[x] = h; 28 s2 = kind[x]; 29 kind[x] = s1; //更新kind[ x ],因为最开始的x的kind就是s1,而之后的kind[ x ]就应该是s1与s2的^运算 30 31 s1 = s1^s2; 32 x = _x; 33 } 34 35 return h; 36 } 37 38 39 void unio(int x,int y) 40 { 41 bool su,sv; 42 int root1 = Find( x ,sv=false); 43 int root2 = Find( y ,su=false); 44 if( root1 == root2 ) sign = sv^su; 45 else { 46 belg[ root2 ] = root1; 47 kind[ root2 ] = !(su^sv); 48 } 49 } 50 51 int main() 52 { 53 freopen("in.txt","r",stdin); 54 int t,nu = 0,a,b,m,n; 55 scanf("%d",&t); 56 while(t--) 57 { 58 sign = true; 59 nu++; 60 scanf("%d%d",&m,&n); 61 memset( kind , false , sizeof( kind ) ); 62 for( int i = 0 ; i <= m ; i++ ) 63 belg[ i ] = i; 64 for( int i = 0 ; i < n ; i++ ) 65 { 66 scanf("%d%d",&a,&b); 67 if(sign) unio(a,b); 68 } 69 printf("Scenario #%d:\n",nu); 70 if(sign) 71 printf("No suspicious bugs found!\n\n"); 72 else 73 printf("Suspicious bugs found!\n\n"); 74 75 } 76 return 0; 77 }
poj 1988
http://poj.org/problem?id=1988
题意:就是给你一群盒子,有两个操作,M就是move,也就是把x盒子移到y盒子的上面。
c就是查询,查询x下面一共有多少个盒子
移动,是指x盒子及其上面的所有的盒子都一起移动到y盒子的上面去。
这个题我原来做过,那个时候不会并查集,然后就用一个结构体来记录其最下面的点,最上面的点,以及这个点下面一共有多少个盒子,然后每次维护。这样就是超时.......然后最近学了并查集,但因为对其理解还不是特别深,不是很会灵活应用,所有也不知道怎么用。最后还是看别人博客,理解别人的思路,再去自己写
思路:维护两个数组,一个是当前盒子下面一共有多少个盒子,以及自己最上面的盒子的个数。
1 #include <stdio.h> 2 #include <string.h> 3 #define maxn 100030 4 5 int belg[ maxn ],rank[ maxn ],top[ maxn ]; 6 7 int Find(int x) 8 { 9 if(belg[x]!=x) 10 { 11 int fa = belg[x]; //每次压缩的时候,顺便更新当前点下面的合资数。 12 belg[x] = Find(fa); 13 rank[x] += rank[fa]; 14 } 15 return belg[x]; 16 } 17 18 void uion(int x,int y) 19 { 20 int root1 = Find( x ); 21 int root2 = Find( y ); 22 if( root1 != root2 ) 23 { 24 belg[ root1 ] = root2; //把x移到y的上面,以及更新x的下面的数量和y最上面的的数量。 25 rank[ root1 ] = top[ root2 ] + 1; 26 top[ root2 ] += top[ root1 ]+1; 27 } 28 29 } 30 31 int main() 32 { 33 // freopen("in.txt","r",stdin); 34 int t,a,b; 35 char x; 36 scanf("%d",&t); 37 for(int i = 0 ; i <= t ; i++) 38 belg[ i ] = i; 39 while(t--) 40 { 41 scanf("%s",&x); 42 if(x=='M') 43 { 44 scanf("%d%d",&a,&b); 45 uion( a , b ); 46 } 47 else 48 { 49 scanf("%d",&a); 50 Find( a ); 51 printf("%d\n",rank[ a ] ); 52 } 53 } 54 return 0; 55 }
poj 2912
http://poj.org/problem?id=2912
题意:有n个人在玩石头剪刀布,这其中就有一个是裁判,而且每一个人都只会出一种手势,要你求是否可以判断出裁判是哪个,并且输出在第几个语句可以判断。
这个题有点像那个食物链的题目,我在判断语句时,也是采取了和食物链一样的写法。
思路:就是枚举每一个人当为裁判,然后进行判断,看看其他与这个裁判无关的语句,是否有矛盾,如果没有矛盾,说明这个人有可能是裁判,如果有,那么这个人就肯定不能当裁判,最后如果没有符合条件的,就输出impossible,如果超过了一个人就输出Can not determine,如果恰好是一个人就输出可以找到,并且把裁判和在哪个语句中可以判断出,在哪个语句中可以判断出的话,这个就是在看最后一个产生矛盾的语句是在哪产生的,因为但枚举的不是这个裁判的时候,这个裁判的语句就会被合并,当找到最后一个矛盾产生的语句时,也就可以判断这个裁判是在哪里被找出来的了。
关于那些语句看不懂可以先去看看我写的食物链。Poj 1182
http://www.cnblogs.com/Tree-dream/p/5709880.html
1 #include <stdio.h> 2 #include <string.h> 3 #define maxn 2005 4 5 struct note{ 6 int x,mark,y; 7 }s[ maxn ]; 8 9 int m,n,belg[ maxn * 3 ]; 10 bool mark[ maxn * 3 ]; 11 12 int Find(int x) 13 { 14 int _x=x,_b; 15 while(_x!=belg[_x]) 16 { 17 _x=belg[_x]; 18 } 19 while(x!=belg[x]) 20 { 21 _b=belg[x]; 22 belg[x]=_x; 23 x=_b; 24 } 25 return _x; 26 } 27 28 bool judge(int x,int y) { 29 if(Find(x)==Find(y)) 30 return true; 31 else return false; 32 } 33 34 void unite(int x,int y) 35 { 36 int root1=Find(x); 37 int root2=Find(y); 38 if(root1!=root2) belg[root1]=root2; 39 } 40 41 void init() 42 { 43 for( int i = 0 ; i <= 3*m ; i++ ) 44 belg[ i ] = i; 45 } 46 47 int main() 48 { 49 // freopen("in.txt","r",stdin); 50 int a,b; 51 char c; 52 while(scanf("%d%d",&m,&n)!=EOF) 53 { 54 init(); 55 for(int i = 1 ; i <= n ; i++ ) 56 { 57 scanf("%d%c%d",&a,&c,&b); 58 getchar(); 59 if(c=='=') 60 { 61 s[ i ].x = a; 62 s[ i ].y = b; 63 s[ i ].mark = 1; 64 } 65 if(c=='<') 66 { 67 s[ i ].x = b; 68 s[ i ].y = a; 69 s[ i ].mark = 0; 70 } 71 if(c=='>') 72 { 73 s[ i ].x = a; 74 s[ i ].y = b; 75 s[ i ].mark = 0; 76 } 77 } 78 int i,sign = 0,falg = 0,y = 0,j; 79 for( i = 0 ; i < m ; i++ ) 80 { 81 init(); 82 for(j = 1 ;j <= n ; j++ ) 83 { 84 if(s[ j ].x != i && s[ j ].y != i) 85 { 86 if(s[ j ].mark == 1) 87 { 88 if(judge(s[ j ].x,s[ j ].y + m )||judge(s[ j ].x,s[ j ].y + 2 * m)) 89 { 90 if( j > y ) y = j; 91 break; 92 } 93 else 94 { 95 unite(s[ j ].x , s[ j ].y); 96 unite(s[ j ].x + m , s[ j ].y + m); 97 unite(s[ j ].x + 2 * m , s[ j ].y + 2 * m); 98 } 99 } 100 else 101 { 102 if(judge( s[ j ].x , s[ j ].y)||judge(s[ j ].x , s[ j ].y + 2 * m)) 103 { 104 105 if( j > y ) y = j; 106 break; 107 } 108 else 109 { 110 unite( s[ j ].x , s[ j ].y + m ); 111 unite( s[ j ].x + m , s[ j ].y + 2 * m ); 112 unite( s[ j ].x + 2 * m , s[ j ].y ); 113 } 114 } 115 } 116 } 117 if(j == n+1) 118 { 119 falg ++; 120 sign = i; 121 } 122 } 123 if(falg == 0) printf("Impossible\n"); 124 else if(falg > 1) printf("Can not determine\n"); 125 else printf("Player %d can be determined to be the judge after %d lines\n",sign,y); 126 127 128 } 129 return 0; 130 }
HDU 3038
题意:n次询问,给出a到b区间的总和,问这n次给出的总和中有几次是和前面已近给出的是矛盾的。
思路:并查集,维护一个之间和的序列就可以。
1 #include <stdio.h> 2 #include <string.h> 3 #define maxn 200020 4 5 int belg[ maxn ],sum[ maxn ]; 6 7 int Find(int x) 8 { 9 if(x!=belg[x]) 10 { 11 int fa = belg[ x ]; 12 belg[ x ] = Find(fa); 13 sum[ x ] += sum[ fa ]; 14 } 15 return belg[ x ]; 16 } 17 18 int main() 19 { 20 // freopen("in.txt","r",stdin); 21 int m,n,a,b,c; 22 23 while(scanf("%d%d",&m,&n)!=EOF) 24 { 25 int ans=0; 26 for( int i = 0 ; i <= m ; i++ ) 27 belg[ i ] = i,sum[ i ] = 0; 28 for( int i = 0 ; i < n ; i++ ) 29 { 30 scanf("%d%d%d",&a,&b,&c); 31 b--; //这里记得-- 32 int root1 = Find(a),root2 = Find(b); 33 if(root1 == root2) 34 { 35 if(sum[ b ]-sum[ a ] != c) ans++; 36 } 37 else 38 { 39 belg[ root2 ] = root1; 40 sum[ root2 ] = sum[ a ]- sum[ b ] + c; 41 } 42 } 43 printf("%d\n",ans); 44 } 45 return 0; 46 }