题意:给定n个村子,以及n个村子之间的相互距离m,给n个村子修路,使它们联通,并知道有的村子已联通,写程序,求最少修多少米路,使村子都联通。
主要思路:使用并查集,图算法,建立从u到v的树,权值为d,把输入内容存在二维数组g【i】【j】里,将已有的顶点连线的权值设为零,建立树状图,对所有的村庄之间的距离进行排序,再利用并查集find函数和merge函数求出所求。
收获:对于数组不用全部写出,写一个下三角就行,因为从a到b与从b到a距离相等。具体事项代码有两种:
其一: for (i = 0; i < n; i++)
for (j = 0; j <= i; j++) {
e[cnt].u = i;
e[cnt].v = j;
e[cnt].d = g[i][j];
cnt++;
}
其二:for(i=0;i<n;i++)
for(j=0;j<n;j++){
if(i>=j)continue;
e[cnt].u = i;
e[cnt].v = j;
e[cnt].d = g[i][j];
cnt++;
}
另外:find函数
可简写为:
int find(int x)
{
if(x!=root[x])
return find(root[x]);
else return x;
}
解题过程同思路
AC代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 101
typedef struct edge {
int u, v;
int d;
} edge;
int g[MAXN][MAXN];
int root[MAXN];
int rank[MAXN];
edge e[5050];
int n;
void makeset(int m)
{
int i;
for (i = 0; i <= m; i++) {
root[i] = i;
}
}
int find(int x)
{
if(x!=root[x])
return find(root[x]);
else return x;
}
void merge(int x, int y)
{
int fx = find(x);
int fy = find(y);
if(fx!=fy)
root[fx]=fy;
}
int cmp(edge a, edge b)
{
return a.d < b.d;
}
int main()
{
int i, j, k;
int a, b, cnt, q;
while (scanf("%d", &n) != EOF) {
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
scanf("%d", &g[i][j]);
}
scanf("%d", &q);
for (i = 0; i < q; i++) {
scanf("%d%d", &a, &b);
g[a-1][b-1] = g[b-1][a-1] = 0;
}
cnt = 0;
for (i = 0; i < n; i++)
for (j = 0; j <= i; j++) {
e[cnt].u = i;
e[cnt].v = j;
e[cnt].d = g[i][j];
cnt++;
}
sort(e, e+cnt, cmp);
int total = 0;
makeset(n);
for (i = 0; i < cnt; i++) {
if (e[i].d == 0)
merge(e[i].u, e[i].v);
else if (find(e[i].u) != find(e[i].v)) {
total += e[i].d;
merge(e[i].u, e[i].v);
}
}
printf("%d\n", total);
}
}