图结构练习——最小生成树
Time Limit: 1000MS Memory limit: 65536K
题目描述
有n个城市,其中有些城市之间可以修建公路,修建不同的公路费用是不同的。现在我们想知道,最少花多少钱修公路可以将所有的城市连在一起,使在任意一城市出发,可以到达其他任意的城市。
输入
输入包含多组数据,格式如下。
第一行包括两个整数n m,代表城市个数和可以修建的公路个数。(n <= 100, m <=10000)
剩下m行每行3个正整数a b c,代表城市a 和城市b之间可以修建一条公路,代价为c。
输出
每组输出占一行,仅输出最小花费。
示例输入
3 2 1 2 1 1 3 1 1 0
示例输出
2 0
提示
来源
赵利强
示例程序
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <queue>
#define inf 999999
using namespace std;
int n, m;
int map[110][110], visit[110], dis[110];
//普里姆算法:首先将所有的边都放到待选区中,也就是dis[], 从顶点开始,遍历这一行也就是两个节点之间最小边,加入到最小生成树中,
// 并把它从待选区中去掉,也就是visit[]赋值为1,遍历所有的节点,根据上一个节点找到的最小边的弧头,再从弧头所在的行开始遍历,直到遍历介结束
void MiniSpanTree(int x)
{
int k, min, sum = 0;
visit[0] = 1; //从顶点n开始遍历,遍历就标记为已遍历
for(int i = 1; i < x; i++) //初始化辅助数组,使每一个辅助数组中存着当前行所有的数据
dis[i] = map[0][i];
for(int i = 1; i < x; i++) //对所有的顶点都遍历
{
min = inf; //初始化最小值,用来寻找这一行中最小的权值
for(int j = 0; j < x; j++) //遍历此行所有的数据,若数据没有遍历过并且小于最小值,赋值为最小值,并记录下当前的位置,
{
if(visit[j] == 0 && min > dis[j])
{
min = dis[j];
k = j; //记录下当前位置,用来寻找下一次要遍历的行
}
}
sum = sum + min; //sum的就是最小生成树的权值
visit[k] = 1; //标记为已遍历,此列不在遍历
for(int j = 0; j < x; j++) //遍历k行所有的数据,把没有遍历过的并且小于当前值得赋值到辅助数组,也就是待选区中,就是
{ //就是把当前节点和k节点的所有边的权值放到待选区中,但是只筛选小于当前权值的
if(visit[j] == 0 && dis[j] > map[k][j])
dis[j] = map[k][j];
}
}
cout << sum << endl;
}
int main()
{
while(cin >> n >> m)
{
memset(visit, 0, sizeof(visit)); //初始化
memset(map, 0, sizeof(map));
for(int i = 0; i < n ; i++) //初始化邻接矩阵,因为为无向图,以对角线对称,对角线处必定为0,其他位置赋值为无限大
{
for(int j = 0; j < n; j++)
{
if(i == j)
map[i][j] = 0;
else
map[i][j] = inf;
}
}
for(int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
if(c < map[a - 1][b - 1]) //因为数组坐标从0开始,而输出的数据的坐标却是从1开始,将其变化为数组中坐标
map[a - 1][b - 1] = map[b - 1][a - 1] = c;
}
MiniSpanTree(n);
}
return 0;
}