数据结构实验之图论六:村村通公路
Time Limit: 1000MS Memory limit: 65536K
题目描述
当前农村公路建设正如火如荼的展开,某乡镇政府决定实现村村通公路,工程师现有各个村落之间的原始道路统计数据表,表中列出了各村之间可以建设公路的若干条道路的成本,你的任务是根据给出的数据表,求使得每个村都有公路连通所需要的最低成本。
输入
连续多组数据输入,每组数据包括村落数目N(N <= 1000)和可供选择的道路数目M(M <= 3000),随后M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个村庄的编号和修建该道路的预算成本,村庄从1~N编号。
输出
输出使每个村庄都有公路连通所需要的最低成本,如果输入数据不能使所有村庄畅通,则输出-1,表示有些村庄之间没有路连通。
示例输入
5 8 1 2 12 1 3 9 1 4 11 1 5 3 2 3 6 2 4 9 3 4 4 4 5 6
示例输出
19
提示
prim算法思路:
任意一个顶点 u 作为生成树的根,
之后往生成树上添加新的顶点 v在添加的顶点 w 和已经在生成树上的顶点v 之间必定存在一条边,
并且该边的权值在所有连通顶点 u和 v 之间的边中取值最小
之后继续往生成树上添加顶点,直至生成树上含有 n-1 个顶点为止。
示例程序
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 1100
using namespace std;
int mp[N][N]; //邻接矩阵存储图
int dis[N]; //标记数组
int vis[N]; //用来记录当前生成树到每个节点的距离
int sum, n, m;//n代表节点数 sum保存生成树的权值总和
void prim()
{
sum=0; //最小生成树的权值总和初始化为0
int mm;
memset(vis, false, sizeof(vis)); //初始化节点均没有被访问
for(int i = 1; i <= n; i++)
{
dis[i] = mp[1][i]; //我们从0号节点开始生成树
}
vis[1] = true; //生成树的根(起点)标记访问
int pos; //用来记录每一次循环找到的节点的编号
int d = 0; //标记变量
for(int i = 1; i < n; i++) //要生成n-1条边,所以循环n-1次
{
mm = INF;
for(int j = 1; j <= n; j++) //对dis数组进行遍历,找到值最小的
{
if(!vis[j] && dis[j] < mm)
{
mm = dis[j];
pos = j;
}
}
if(mm == INF) //如果在此跳出循环,表示有城市之间不能连通
{
d = 1;
break;
}
sum += mm; //加上找到的最小权值
vis[pos] = true; //标记找到的该节点被访问
for(int j = 1; j <= n; j++) //更新dis数组
{
if(!vis[j] && dis[j] > mp[pos][j])
{
dis[j] = mp[pos][j]; //如果该点还没有被访问过,
//更新生成树到该点的距离;
}
}
}
if(d == 0)
printf("%d\n", sum); //n-1次循环完毕后输出权值总和
else
printf("-1\n");
}
int main()
{
while(cin >> n >> m)
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++) //对mp数组初始化
{
if(i == j)
mp[i][j] = 0;
else
mp[i][j] = INF;
}
}
while(m--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if(mp[a][b] > c) //如果存在重边,取最小值
mp[a][b] = mp[b][a] = c;
}
prim(); //执行普利姆算法
}
return 0;
}