并查集
主要解决图的连通性问题,比如:
1、随意给你两个点,让你判断它们是否连通;
2、问你整幅图一共有几个连通分支;
初始化:
void init(int size) { for(int i = 0; i < size; i++) pre[i] = i; }
代码(非递归):
int find(int x) //查找根节点 { int r = x; while(pre[r] != r) r = pre[r]; //返回根节点 r int i = x , j ; while(i != r) //路径压缩 { j = pre[i]; // 在改变上级之前用临时变量 j 记录下他的值 pre[i] = r ; //把上级改为根节点 i = j; } return r ; } void join(int x,int y) //判断x y是否连通 { int fx = find(x); int fy = find(y); if(fx != fy) //如果已经连通,就不用管了; 如果不连通,就把它们所在的连通分支合并起 pre[fx]=fy; }
递归法:
int find(int x) { if (x != pre[x]) pre[x] = find(pre[x]); return pre[x]; }
求连接非连通图,需要几条边:
#include <iostream> using namespace std; int N, E, Answer; int pre[1000]; int find(int x) { int r = x; while(pre[r] != r) //找父亲 r = pre[r]; int i = x, j; while(i != r) //路径压缩 { j = pre[i]; pre[i] = r; i = j; } return r; } int find2(int x) //递归 { if (x != pre[x]) pre[x] = find(pre[x]);
return pre[x]; } int main() { int x, y, p1, p2; while(cin >> N, N) //顶点数 { Answer = N-1; //N个顶点需要N-1条边 for(int i = 1; i <= N; i++) pre[i] = i; //每个顶点的父亲都是自己 cin >> E; //边数 while(E--) { cin >> p1 >> p2; x = find(p1); y = find(p2); if(x != y) //如果是不连通的,把这两个分支连起来, 分支的总数就减少了1,还需建的路也就减了1 { pre[y]=x; Answer--; } //如果两点已经连通了,那么这条路只是在图上增加了一个环 //对连通性没有任何影响,无视掉 } cout << Answer << endl; //最后输出还要修的路条数 }
}
输入:
4 2 1 2 3 4 7 5 1 2 2 3 3 4 1 5 6 7