路径优化——见过很多的版本——这个应该是见过最多的一个啦
在FInd函数中查找到树根后,不要忙着退出
设定一个变量tmp在模拟找一次,但是中途所有经过的点
int Find(int x) { int rt = x,tmp; while(pre[rt] != rt)rt = pre[rt]; while(x != rt){tmp = pre[x];pre[x] = rt;x = tmp;} return rt; }
然后就是按照树的深度进行合并处理
void join(int a,int b) { int ra = Find(a); int rb = Find(b); if(ra == rb)return; if(hei[ra] == hei[rb]) { pre[rb] = ra; ++hei[ra]; } else if(hei[ra] > hei[rb]) pre[rb] = ra; else pre[ra] = rb; }
接下来就是常规的并查集了
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> using namespace std; const int maxn = 1e4 + 10; int pre[maxn]; int hei[maxn]; void init(int n) { for(int i = 0;i <= n;i++) { pre[i] = i; hei[i] = 1; } } int Find(int x) { int rt = x,tmp; while(pre[rt] != rt)rt = pre[rt]; while(x != rt){tmp = pre[x];pre[x] = rt;x = tmp;} return rt; } void join(int a,int b) { int ra = Find(a); int rb = Find(b); if(ra == rb)return; if(hei[ra] == hei[rb]) { pre[rb] = ra; ++hei[ra]; } else if(hei[ra] > hei[rb]) pre[rb] = ra; else pre[ra] = rb; } int main() { int n,m; while(~scanf("%d",&n),n) { scanf("%d",&m); int a,b; init(n); for(int i = 1;i <= m;i++) { scanf("%d%d",&a,&b); join(a,b); } int ans = n - 1; for(int i = 1;i <= n;i++) { if(pre[i] != i) ans--; } printf("%d ",ans); } return 0; }
这个题以入门的畅通工程为例子