1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 int f[1010];//记录当前i的前驱(画完图是树形结构) 5 6 int find(int x) //查找根节点 7 { 8 int r=x; 9 while(f[r]!=r) 10 r=f[r]; 11 int i=x,j; 12 while(i!=r) 13 { 14 j=f[i]; 15 f[i]=r; 16 i=j; 17 } 18 return r; 19 } 20 21 int main() 22 { 23 int n,m,a,b; 24 while(scanf("%d%d",&n,&m),n) 25 { 26 for(int i=0;i<=n;i++) 27 f[i]=i; 28 for(int i=0;i<m;i++) 29 { 30 scanf("%d%d",&a,&b); 31 int x=find(a),y=find(b);//查找祖先,判断x,y是否为一个祖先 32 if(x!=y) // 当ab的帮派不是一个的话,合并 在一起即一个大哥 33 f[x]=f[y]; 34 } 35 int c=0; 36 for(int i=1;i<=n;i++) 37 if(f[i]==i) 38 c++; 39 printf("%d ",c-1); 40 } 41 return 0; 42 } 43
我的理解:
并查集 先是把各个顶点当成一个集合,构成n个集合后,用线段把集合连接起来,判断是否为连通图即判断f数组i位置元素是否等于i,如有一个则为连通图否则为非连通图
find函数把线段的两个顶点x,y找到他所在集合的老大,判断线段的两个端点是否为一个老大,即用f【】数组找,f数组记录的前驱;
找到两个老大之后,如不相等就把两个老大集合,合并起来。