题目: http://acm.hdu.edu.cn/showproblem.php?pid=1102
本题的给输入是矩阵的存储,但最后又给出已经修好的路,所以我先用矩阵存储输入,再将其中的边提出来,用
struct Edge{
int u,v,w;
};
存储,因为下面用kruskal就方便了。(这个题目首先你要知道用kruskal)
对于已经修好的路的顶点,用并查集合并其顶点集合。
接下来扫描顶点1到N,找出其父亲结点,我用set<int> rgSet存储,很方便找出1到N化分成的集合数目。
然后就是再加入minnum条边就行了。
#include <iostream>
#include <cstdio>
#include <functional>
#include <set>
#include <algorithm>
using namespace std;
#define MAXV 111
#define INF 32767
struct Tree {
int parent;
int rank;
} t[MAXV];
struct Edge {
int u, v, w;
bool operator <(const Edge &elem) const {
return w < elem.w;
}
} edge[MAXV*MAXV];
struct Graph {
int matrix[MAXV][MAXV];
int n;
};
void Make_Set(int n) {
int i;
for (i = 0; i <= n; ++i) {
t[i].parent = i;
t[i].rank = 0;
}
}
int Find_Set(int x) {
int i, j, r;
r = x;
while (t[r].parent != r) {
r = t[r].parent;
}
i = x;
while (t[i].parent != r) {
j = t[i].parent;
t[i].parent = r;
i = j;
}
return r;
}
int Union_Set(int x, int y) {
if (t[x].rank > t[y].rank) {
t[y].parent = x;
return x;
} else {
t[x].parent = y;
if (t[x].rank == t[y].rank)
t[y].rank++;
return y;
}
}
int Kruskal(int N,int E) {
int i, j, a, b, Q;
int s1, s2;
int ret = 0;
sort(edge, edge + E); // 注意这里是对边sort
Make_Set(N); // 这里是对顶点集合1到N初始化, 这两行的别晕了,run time error 好多次才找出来。。汗。。
// ----------------
scanf("%d", &Q);
for (i = 0; i < Q; ++i) {
scanf("%d%d", &a, &b);
a = Find_Set(a);
b = Find_Set(b);
if (a != b)
Union_Set(a, b);
}
set<int> rgSet;
for(i=1;i<=N;++i)
rgSet.insert(Find_Set(i));
i=rgSet.size();
i-=1;
j = 0;
while (i > 0) {
s1 = Find_Set(edge[j].u);
s2 = Find_Set(edge[j].v);
if (s1 != s2) {
Union_Set(s1, s2);
ret += edge[j].w;
--i;
}
++j;
}
rgSet.clear();
return ret;
}
int main() {
// freopen("input.txt", "r", stdin);
int N,E;
int i, j;
Graph g;
while (scanf("%d", &N) != EOF) {
E=0;
for (i = 0; i < N; ++i)
for (j = 0; j < N; ++j)
scanf("%d", &g.matrix[i][j]);
for (i = 0; i < N; ++i)
for (j = i + 1; j < N; ++j) {
edge[E].u = i+1;
edge[E].v = j+1;
edge[E].w = g.matrix[i][j];
E+=1;
}
printf("%d\n", Kruskal(N,E));
}
return 0;
}