Description
当前农村公路建设正如火如荼的展开,某乡镇政府决定实现村村通公路,工程师现有各个村落之间的原始道路统计数据表,表中列出了各村之间可以建设公路的若干条道路的成本,你的任务是根据给出的数据表,求使得每个村都有公路连通所需要的最低成本。
Input
连续多组数据输入,每组数据包括村落数目N(N <= 1000)和可供选择的道路数目M(M <= 3000),随后M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个村庄的编号和修建该道路的预算成本,村庄从1~N编号。
Output
输出使每个村庄都有公路连通所需要的最低成本,如果输入数据不能使所有村庄畅通,则输出-1,表示有些村庄之间没有路连通。
Sample
Input
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
Output
19
Hint
算法讲解:
Prim和Kruskal
学习Kruska算法需要先掌握并查集:
并查集
//Prim
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 1111;
int mp[N][N], book[N];
int prim(int n)//最小生成树普利姆算法,加点法,适合稠密图
{
int dp[N];
for(int i = 1; i <= n; i++)
{
book[i] = 0;
dp[i] = mp[1][i];//初始化。1点与i点之间的权值
}
book[1] = 1;//第一个不进行循环
int sum = 0;
int minn;
int flag;
for(int i = 1; i < n; i++)
{
minn = INF;
flag = -1;
for(int j = 1; j <= n; j++)
{
if(!book[j] && dp[j] < minn)
{
minn = dp[j];
flag = j;
}
}
if(minn == INF)
return -1;
book[flag] = 1;
sum += minn;
for(int j = 1; j <= n; j++)
{
if(!book[j] && dp[j] > mp[flag][j])
{
dp[j] = mp[flag][j];
}
}
}
return sum;
}
int main()
{
int n, m;//n个村庄,m条路
while(cin >> n >> m)
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)//对图进行初始化
{
if(i == j)
mp[i][j] = 0;
else
mp[i][j] = INF;
}
}
while(m--)
{
int u, v, k;
cin >> u >> v >> k;
if(k < mp[u][v])
{
mp[u][v] = mp[v][u] = k;
}
}
int sum;
sum = prim(n);
cout << sum << endl;
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N = 1005, M = 3005;
int Next[N];
struct node
{
int u, v, len;
} edge[M];
int cmp(node a, node b)
{
return a.len < b.len;
}
void init(int n)//并查集初始化
{
for(int i = 1; i <= n; i++)
Next[i] = i;
}
int find_root(int i)
{
if(Next[i] == i)
return Next[i];
else
{
Next[i] = find_root(Next[i]);
return Next[i];
}
}
int merage(int u, int v)
{
int t1 = find_root(u), t2 = find_root(v);
if(t1 != t2)
{
Next[t1] = Next[t2];
return 1;
}
else
return 0;
}
int main()
{
int n, m;
while(cin >> n >> m)
{
for(int i = 1; i <= m; i++)
{
cin >> edge[i].u >> edge[i].v >> edge[i].len;
}
sort(edge + 1, edge + 1 + m, cmp);//将边按权值从小到大排序
int sum = 0, flag = 0;
init(n);
for(int i = 1; i <= m; i++)
{
if(merage(edge[i].u, edge[i].v))
sum += edge[i].len;
}
for(int i = 1; i <= n; i++)
{
if(Next[i] == i)
flag++;
}
if(flag == 1)
cout << sum << endl;
else
cout << -1 << endl;
}
return 0;
}