对于第一次女生训练的析题相关:
首先是第一题:
How Many Tables
One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.
For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 #include <math.h>
 6 
 7 using namespace std;
 8 
 9 int pre[1001];
10 struct node{
11     int x;
12     int y;
13 }a[1001];
14 
15 int find(int x){
16     int r=x;
17     while(pre[r]!=r)
18         r=pre[r];
19     return r;
20 }
21 
22 int main(){
23     int N,M,i,num;
24     int T;
25     scanf("%d",&T);
26     while(T--){
27         scanf("%d%d",&N,&M);//N表示朋友个数,M表示关系条数
28         num=N;   //N个朋友最多坐n桌之间
29         for(i=1;i<=N;i++)   //pre数组初始化
30             pre[i]=i;
31         for(i=1;i<=M;i++){
32             scanf("%d%d",&a[i].x,&a[i].y);
33             //在这里连接认识的朋友们
34             int b=find(a[i].x);
35             int c=find(a[i].y);
36             if(b!=c){
37                 pre[c]=b;
38                 num--;
39             }
40         }
41         printf("%d\n",num);      //对于输出格式有变
42     }
43     return 0;
44 }
那么我决定首先去刷并查集的水题,学姐说可以先刷水题,再慢慢提高难度,要建立自己的信心。
以下为A的水题:
A – 畅通工程 HDU 1232(题意大致)
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?
Input
测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 
注意:两个城市之间可以有多条道路相通,
 1 #include<iostream>
 2 #include<stdio.h>
 3 
 4 int pre[1001];
 5 
 6 int find(int x){       //查找根节点
 7     int r=x;
 8     while(pre[r]!=r)    //返回根节点
 9         r=pre[r];
10     int i=x,j;
11     while(i!=r){      //路径压缩
12         j=pre[i];   //在改变上级之前用临时变量j记录下它的值
13         pre[i]=r;   //把自己的上级直接改为根节点,终极Boss
14         i=j;        //接着去改变自己原本的上级它的上级为终极Boss
15     }
16     return r;
17 }
18 
19 void join(int a,int b){
20     //判断a与b是否连通
21     //如果已经连通,那么可以不用管
22     //如果不连通,就把它们所在的连通分支合并起来
23     int fx = find(a);
24     int fy = find(b);
25     if(fx!=fy)
26         pre[fx]=fy; //没有优化,产生的树可能是畸形树
27 }
28 
29 int main(){
30     int n;
31     while(scanf("%d",&n)&&n!=0){
32         int m,i,a,b,ans;
33         for(i=1;i<=n;i++) //对pre数组的初始化
34             pre[i]=i;
35         //memset(pre,0,pre+n);
36         scanf("%d",&m);
37         for(i=1;i<=m;i++){
38             scanf("%d%d",&a,&b);
39             join(a,b);
40         }
41         for(ans=0,i=1;i<=n;i++){
42             if(pre[i]==i)
43                 ans++;
44         }
45         ans-=1;
46         printf("%d\n",ans);
47     }
48     return 0;
49 }
再来是
B - 小希的迷宫 | Is it a tree ? HDU 1272 (大致题意)
上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走。但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你帮忙判断她的设计图是否符合她的设计思路。比如下面的例子,前两个是符合条件的,但是最后一个却有两种方法从5到达8。
Input
输入包含多组数据,每组数据是一个以0 0结尾的整数对列表,表示了一条通道连接的两个房间的编号。房间的编号至少为1,且不超过100000。每两组数据之间有一个空行。 
整个文件以两个-1结尾。 
其实觉得这题一开始看会有些晕,就像训练里面那题,也需要看久一些,才能正确使用模板。看来我对并查集的理解还是不够。。。。
而且这道题错了好几次,输出的小错误在此就不需提了,是一些算法顺序上的错误,模板不够熟啊不够熟!
最终AC代码:
 1 #include<iostream>
 2 #include<stdio.h>
 3 using namespace std;
 4 
 5 const int N=100010;
 6 int pre[N],s;
 7 int num[N],v[N];
 8 
 9 void Init(){
10     for(int i=1;i<=N;i++){
11         pre[i]=i;
12         v[i]=num[i]=1; //v[]记录状态起始为1
13     }
14 }
15 int find(int x){       //查找根节点
16     int r=x;
17     while(pre[r]!=r)    //返回根节点
18         r=pre[r];
19         /*int i=x,j;
20         while(i!=r){      //路径压缩
21         j=pre[i];   //在改变上级之前用临时变量j记录下它的值
22         pre[i]=r;   //把自己的上级直接改为根节点,终极Boss
23         i=j;        //接着去改变自己原本的上级它的上级为终极Boss
24 }*/
25     return r;
26 }
27 
28 int join(int a,int b){
29     //判断a与b是否连通
30     int fx = find(a);
31     int fy = find(b);
32     if(fx==fy){       //此时如果连通那么就会使这棵树产生回路
33         return 1;
34     }
35     else{
36         pre[fy]=fx; //当两个房间不属于同一棵树时连接
37         num[fx]+=num[fy];
38         s=num[fx];
39         return 0;
40             //没有优化,产生的树可能是畸形树
41     }
42 }
43 
44 int main(){
45     int i,a,b;
46     while(scanf("%d%d",&a,&b)&&(a!=-1||b!=-1)){
47         Init();
48         if(a==0&&b==0){   //判断空树情况
49             printf("Yes\n");
50             continue;
51         }
52         int ok=join(a,b),n=v[a]+v[b];  //ok记录是否存在环,n记录节点总数  
53         v[a]=v[b]=0;
54         for(i=2;i<=N;i++){
55             scanf("%d%d",&a,&b);
56             if(a==0&&b==0)
57                 break;
58             n+=(v[a]+v[b]);
59             v[a]=v[b]=0;
60             ok+=join(a,b);
61         }
62         if(ok)
63             printf("No\n");
64         else{
65             if(s==n)
66                 printf("Yes\n");
67             else
68                 printf("No\n");
69         }
70     }
71     return 0;
72 }
对于并查集的总结先到这里,还需要大大的加深学习力度。
