POJ2524 Ubiquitous Religions 并查集

Problem Address:http://poj.org/problem?id=2524

 

简单的并查集。

 

这个也是我第一次写并查集。刚好想学,又刚好开始切一个师兄的题,刚好切没几道就碰到并查集。便顺手学下来。

 

这道题是并查集的简单合并。

 

复杂一点的我也没试过,不知道是不是得生成二叉树之类的来进行优化。

 

便直接开了一个数组来模拟树。

 

用father记录根节点,用next记录下一个结点。每读入一个数,就把第一个集合插入到第二个集合之中(有待优化),并把第一个集合的根节点修改为第二个集合的根节点。最后只要计算不同的集合个数就行(visited用来标记集合)。

 

#include <iostream> using namespace std; int father[50005],next[50005]; bool visited[50005]; int main() { int n,m,i,x,y,temp,index=1,roottemp; while(scanf("%d %d", &n, &m)!=EOF) { if (n==0 && m==0) break; for (i=1; i<=n; i++) { father[i] = i; next[i] = 0; visited[i] = false; } for (i=0; i<m; i++) { scanf("%d %d", &x, &y); if (father[x]!=father[y]) { temp = father[x]; roottemp = temp; father[temp] = father[y]; while(next[temp]!=0) { temp = next[temp]; father[temp] = father[y]; } next[temp] = next[y]; next[y] = roottemp; } } for (i=1,temp=0; i<=n; i++) { if (!visited[i]) { temp++; x = father[i]; visited[x] = true; while(next[x]!=0) { x = next[x]; visited[x] = true; } } } printf("Case %d: %d/n", index, temp); index++; } return 0; }

 

一次AC后,在discuss里看到有人不用visited的。然后改了一下,在输入过程中用result记录。效果差不多。

 

#include <iostream> using namespace std; int father[50005],next[50005]; int main() { int n,m,i,x,y,temp,index=1,roottemp,result; while(scanf("%d %d", &n, &m)!=EOF) { if (n==0 && m==0) break; result = n; for (i=1; i<=n; i++) { father[i] = i; next[i] = 0; } for (i=0; i<m; i++) { scanf("%d %d", &x, &y); if (father[x]!=father[y]) { temp = father[x]; roottemp = temp; father[temp] = father[y]; while(next[temp]!=0) { temp = next[temp]; father[temp] = father[y]; } next[temp] = next[y]; next[y] = roottemp; result--; } } printf("Case %d: %d/n", index, result); index++; } return 0; }

你可能感兴趣的:(优化,IM)