现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
输入格式说明:
输入数据包括城镇数目正整数N(<=1000)和候选道路数目M(<=3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。
输出格式说明:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出-1,表示需要建设更多公路。
样例输入与输出:
序号 | 输入 | 输出 |
1 | 6 15 1 2 5 1 3 3 1 4 7 1 5 4 1 6 2 2 3 4 2 4 6 2 5 2 2 6 6 3 4 6 3 5 1 3 6 1 4 5 10 4 6 8 5 6 3 | 12 |
2 | 3 1 2 3 2 | -1 |
3 | 5 4 1 2 1 2 3 2 3 1 3 4 5 4 | -1 |
分析:
这是一道求最小生成树的问题,给出城镇和城镇之间的费用作为权重,求出要连通所有城镇的最少费用,也就是求出这个图的最小生成树,当然不能连通时输出-1
我的思路就是先用邻接矩阵的方法存储图,然后就运用Prim算法求出这个图的最小生成树,最后输出最少费用dist
源码:
#include<iostream>
#include<stack>
#define MAXNUM 100000
#define NOEXIT -1
using namespace std;
int minDist(int dist[],bool flag[],int n) //求最小的dist
{
int mindist = MAXNUM;
int icount = NOEXIT;
for(int i=1;i<n;i++)
{
if(dist[i] < mindist && flag[i] == false)
{
icount = i;
mindist = dist[i];
}
}
return icount;
}
int Prim(int *data[], int n, int m)
{
// 集合: 用来存储收集到的结点
stack<int> sta;
sta.push(0);
// dist: 记录长度
int *dist = new int[n];
for(int i=0;i<n;i++)
{
dist[i] = MAXNUM;
}
dist[1] = 0;
// collected: 标记是否被访问
bool *collected = new bool[n];
for(int i=0;i<n;i++)
{
collected[i] = false;
}
// parent: 记录树的结构
int *parent = new int[n];
for(int i=0;i<n;i++)
{
parent[i] = NOEXIT;
}
// output: 最终结果
int output = 0;
while (1)
{
int V = minDist(dist, collected, n);
if (V == NOEXIT)
break;
sta.push(V);
output += dist[V];
dist[V] = 0;
collected[V] = true;
for(int W=1; W<n; W++)
{
if(data[V][W] != MAXNUM // 如果W是V的邻接点
&& collected[W] == false // 如果W没有被访问
&& data[V][W] < dist[W])
{
dist[W] = data[V][W];
parent[W] = V;
}
}
}
if(sta.size() != n)
return NOEXIT;
else
return output;
}
int main()
{
int n,m;
cin>>n>>m;
n++;
//用邻接矩阵存储图
int **data = new int*[n];
for(int i=0; i<n; i++)
{
data[i] = new int[n];
}
//初始化
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
data[i][j] = MAXNUM;
}
}
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
data[a][b] = c;
data[b][a] = c;
}
cout<<Prim(data,n,m) <<endl;
return 0;
}