数据量不大,直接暴力过。我用了Prime,过程写在注释中。
#include<iostream>
#include<cstring>
#include<algorithm>
#pragma warning(disable: 4996)
using namespace std;
const int NN = 100 + 5, INF = 99999999;
int a[NN][NN], f[NN];
int find(int x)
{//找到根节点
if (x == f[x]) return x;
f[x] = find(f[x]);
return f[x];
}
int mer(int x, int y)
{
x = find(x);
y = find(y);
if (x != y)
f[x] = y;//这里是把传入参数x的根节点的父节点改成传入参数y的根节点
return 1;
}
int main()
{
int n, q, x, y, sum;
while (scanf("%d", &n) != EOF)
{
sum = 0;
if (n == 0) break;
for (int i = 0; i < n; i++)//每个顶点的根节点记录为自己
f[i] = i;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
scanf("%d", &x);
x == 0 ? a[i][j] = INF : a[i][j] = x;//0的话记录为无穷大
}
scanf("%d", &q);
for (int i = 0; i < q; i++)
{
scanf("%d %d", &x, &y);
mer(x - 1, y - 1);//代码数据记录从0开始,题目从1开始,故需要-1
}
while (1)
{//用Prime算法求解,找到所有边中连接两个不同集合的最小边,然后把这条边的两个顶点连接起来,不断重复直至覆盖所有顶点
int min0 = INF, flag = 1;
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
if (find(i) != find(j) && a[i][j] < min0)
{
min0 = a[i][j];
x = i;
y = j;
flag = 0;
}
if (flag) break;
mer(x, y);
sum += min0;
a[x][y] = INF;
//a[y][x] = INF;
}
cout << sum << endl;
}
return 0;
}