实现代码:
class UnitFind
{
enum{Max_size = 101};
public:
UnitFind()
{
ans = 0;
int i = 0;
for(i = 0; i < Max_size; i++)
{
father[i] = i;
rank[i] = 0; //树的深度
}
}
int FindSet(int x)
{
if(x != father[x]) //最顶的那个祖先永远满足 x = father[x];
{
father[x] = FindSet(father[x]); //路径压缩
}
return father[x];
}
void unionSet(int x, int y)
{
link(FindSet(x), FindSet(y));
return;
}
void link(int x, int y) //两个祖先,按秩合并
{
if(x == y) return;
if(rank[x] > rank[y])
{
father[y] = x; //将深度小的合并到深度大的那棵树上
}
else
{
if(rank[x] == rank[y])
{
rank[y]++;
}
father[x] = y;
}
}
private:
int father[Max_size];
int rank[Max_size];
};
练习一道ACM题,解答:2421
http://poj.org/problem?id=2421
Constructing Roads
Description
There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected.
We know that there are already some roads between some villages and your job is the build some roads such that all the villages are connect and the length of all the roads built is minimum.
Input
The first line is an integer N (3 <= N <= 100), which is the number of villages. Then come N lines, the i-th of which contains N integers, and the j-th of these N integers is the distance (the distance should be an integer within [1, 1000]) between village i and village j.
Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains two integers a and b (1 <= a < b <= N), which means the road between village a and village b has been built.
Output
You should output a line contains an integer, which is the length of all the roads to be built such that all the villages are connected, and this value is minimum.
Sample Input
3 0 990 692 990 0 179 692 179 0 1 1 2Sample Output
179
题意:找出最短路径,并消除已经建好的路的长度,我利用并查集,建立了合并找到最短路的方案,首先输入所有的路,并将已经建好的路的长度置为0, 之后对要修的路进行qsort快速排序,使其从小到大排列,之后利用并查,现将小的找到其father进行并查,这样就可以使后来的大的长度的father与前面的小的father相同,就直接return即可,这样
就找到了最短路径了。
代码:
#include "iostream"
using namespace std;
class UnitFind
{
enum{Max_size = 101};
public:
UnitFind()
{
ans = 0;
int i = 0;
for(i = 0; i < Max_size; i++)
{
father[i] = i;
rank[i] = 0; //树的深度
}
}
int FindSet(int x)
{
if(x != father[x]) //最顶的那个祖先永远满足 x = father[x];
{
father[x] = FindSet(father[x]); //路径压缩
}
return father[x];
}
void unionSet(int x, int y, int w)
{
link(FindSet(x), FindSet(y), w);
return;
}
void link(int x, int y, int w) //两个祖先,按秩合并
{
if(x == y) return;
if(rank[x] > rank[y])
{
father[y] = x; //将深度小的合并到深度大的那棵树上
}
else
{
if(rank[x] == rank[y])
{
rank[y]++;
}
father[x] = y;
}
ans += w;
}
void print()
{
cout << ans;
}
private:
int ans;
int father[Max_size];
int rank[Max_size];
};
typedef struct route
{
int x_node;
int y_node;
int weight;
}route;
int cmp(const void *a, const void *b)
{
return (*(route *)a).weight - (*(route *)b).weight;
}
#define Max 101
int main()
{
route Route[Max*Max/2];
int map[Max][Max];
memset(Route, 0, Max*Max/2*sizeof(Route[0]));
memset(map, 0, Max*Max*sizeof(map[0][0]));
int num;
cin >> num;
for(int i = 0; i < num; i++)
{
for(int j = 0; j < num; j++)
{
cin >> map[i][j];
}
}
//if it has created, wo defined it as 0;
int Q;
cin >> Q;
unsigned x, y;
for(int i = 0; i < Q; i++)
{
cin >> x >> y;
x--; y--;
map[x][y] = 0;
map[y][x] = 0;
}
int k = 0;
for(int i = 0; i < num; i++) //create finished
{
for(int j = i+1; j < num; j++)
{
Route[k].x_node = i;
Route[k].y_node = j;
Route[k].weight = map[i][j]; //just record unrepeat
k++;
}
}
//begin accumulate
qsort(Route, k, sizeof(Route[0]), cmp); //small to big
UnitFind unitSon;
for(int i = 0; i < k; i++)
{
unitSon.unionSet(Route[i].x_node, Route[i].y_node, Route[i].weight); //因为首先经过了排序,所以并查时从小到大,前面的并查father时已经出现了,会出现相等的case.
}
unitSon.print();
return 0;
}