题目描述 Description
一个国家有n个城市。若干个城市之间有电话线连接,现在要增加m条电话线(电话线当然是双向的了),使得任意两个城市之间都直接或间接经过其他城市有电话线连接,你的程序应该能够找出最小费用及其一种连接方案。
输入描述 Input Description
输入文件的第一行是n的值(n<=100).
第二行至第n+1行是一个n*n的矩阵,第i行第j列的数如果为0表示城市i与城市j有电话线连接,否则为这两个城市之间的连接费用(范围不超过10000)。
输出描述 Output Description
输出文件的第一行为你连接的电话线总数m,第二行至第m+1行为你连接的每条电话线,格式为i j,(i<j), i j是电话线连接的两个城市。输出请按照Prim算法发现每一条边的顺序输出,起始点为1.
第m+2行是连接这些电话线的总费用。
样例输入 Sample Input
5
0 15 27 6 0
15 0 33 19 11
27 33 0 0 17
6 19 0 0 9
0 11 17 9 0
样例输出 Sample Output
2
1 4
2 5
17
数据范围及提示 Data Size & Hint
n<=100
这个题是非常标准的Prim最小生成树的问题。他的输出顺序可以先用一个二维下标为2的数组存储,最后结束的时候打印出来即可。
直接上代码
/*************************************************************************
> File Name: 电话连线.c
> Author: zhanghaoran
> Mail: 467908670@qq.com
> Created Time: 2015年05月25日 星期一 10时03分14秒
************************************************************************/
#include <stdio.h>
#include <string.h>
#define INF 100000
int Prim(int a[][100], int n){
int low[100];
int b[100][2];
int used[100];
int closeset[100];
int i, j, k, min;
int flag = 0;
int icount = 0;
int count = 0;
int t = 0;
for(i = 0; i < n ; i ++){
low[i] = a[0][i];
used[i] = 0;
closeset[i] = 0;
}
used[i] = 0;
for(i = 0; i < n - 1; i++){
j = 0;
min = INF;
for(k = 1; k < n; k ++)
if(!used[k] && low[k] < min){
j = k;
min = low[k];
if(min == 0){
flag = 1;
break;
}
}
used[j] = 1;
count += min;
if(flag == 0){
icount ++;
b[t][0] = j + 1 < closeset[j] + 1 ? j + 1 : closeset[j] + 1;
b[t][1] = j + 1 > closeset[j] + 1 ? j + 1 : closeset[j] + 1; //用来存储最后输出的数据
t ++;
}
flag = 0; //如果中间连通的话那么就不将其存储
for(k = 1; k < n; k ++)
if(!used[k] && a[j][k] < low[k]){
low[k] = a[j][k];
closeset[k] = j;
}
}
printf("%d\n", icount);
for(i = 0; i < icount; i++){
printf("%d %d\n", b[i][0], b[i][1]);
}
return count;
}
int main(void){
int n;
int a[100][100];
int i, j;
scanf("%d", &n);
for(i = 0; i < n; i ++){
for(j = 0; j < n; j ++){
scanf("%d", &a[i][j]);
}
}
printf("%d\n", Prim(a, n));
}