题目描述
茫茫大海上有许多小岛,为了避免不可预知的危险,人们只能在两岛之间直线行船。先辈们找到了一个岛之间的最佳航海路线,所谓最佳航海路线,就是能够连接所有的岛且路线长度总和最小。但随着航海业的日益发展,这条路线变得日益拥挤,于是海运局聘请你寻找另外一个尽可能佳的路线,所经过的小岛与原路线不完全相同就可。
输入格式
有多组测试数据。第一行两个整数 N,M (2<=N<=500),表示有 N 个岛,编号 1 到 n。之后 M 行,每行 3 个整数 u,v,w,表示从 u 岛到 v 岛的直线长度为 w。
输出格式
输出一行两个数,原路线长度和与新路线长度和,如果无法找到新路线,输出-1。
样例
input
4 6 1 2 2 2 3 2 3 4 2 4 1 2 1 3 1 2 4 1 3 2 1 2 2 2 3 2output
4 4 4 -1
思路:题目要求输出的答案其实是最小生成树的长度以及(非严格)次小生成树长度。次小生成树是在最小生成树的基础上,遍历所有未被选中的边,尝试着将其加入最小生成树,并删去由此产生的环中除了新加入的这条边外最长的那条边(即留下的边都是最短的那些,保证新的树长度尽可能小),选取遍历结果中长度最小的树,即为次小生成树,由于这样产生的树长度可能与最小生成树相同,因此这种次小生成树是非严格的,但题目描述的正是这种非严格的次小生成树。次小生成树算法可以由Prim算法改良,需要额外的数组记录未被选中的边集,以及每两个点之间最长的边(用动态规划思想实现),代码如下:
#include <iostream>
#include <cstring>
#define INF 0x3f3f3f3f
using namespace std;
/*Prim算法需要的全局变量*/
bool visited [501];
int cost[501][501];
int pre[501];
int lowc[501];
/*Prim算法需要的全局变量*/
/*次小生成树需要的全局变量*/
bool used[501][501]; //标记边是否被用在最小生成树中
int max_edge[501][501]; //记录两个点之间最长的边的长度
/*次小生成树需要的全局变量*/
int Prim(int n)
{
int total = 0, index;
for(int i=2; i<=n; ++i){
lowc[i] = cost[1][i];
if(lowc[i]<INF)
pre[i] = 1;
}
pre[1] = 0;
visited[1] = true;
for(int i=2; i<=n; ++i){
int min_e = INF;
for(int j=2; j<=n; ++j){
if(!visited[j] && lowc[j]<min_e){
min_e = lowc[j];
index = j;
}
}
total += lowc[index];
visited[index] = true;
used[index][pre[index]] = used[pre[index]][index] = true; //标记这条边用过了
for(int j=2; j<=n; ++j){
if(!visited[j] && cost[index][j]<lowc[j]){
lowc[j] = cost[index][j];
pre[j] = index;
}
if(visited[j] && j!=index) //更新最长边
max_edge[index][j] = max_edge[j][index] = max(max_edge[pre[index]][j], lowc[index]);
}
}
return total;
}
int second_st(int n, int MST)
{
int total = INF;
/*遍历所有边*/
for(int i=1; i<=n; ++i)
for(int j=i+1; j<=n; ++j){
if(!used[i][j] && cost[i][j]<INF)
total = min(MST-max_edge[i][j]+cost[i][j], total);
}
if(total == INF) //找不到次小生成树
total = -1;
return total;
}
int main()
{
int N, M, u, v, w, MST, SMT;
while(cin>>N>>M){
memset(visited, 0, sizeof(visited));
memset(max_edge, 0, sizeof(max_edge));
memset(used, 0, sizeof(used));
for(int i=1; i<=N; ++i)
for(int j=1; j<=N; ++j)
cost[i][j] = INF;
for(int i=0; i<M; ++i){
cin>>u>>v>>w;
cost[u][v] = w;
cost[v][u] = w;
}
MST = Prim(N);
SMT = second_st(N, MST);
cout<<MST<<' '<<SMT<<endl;
}
return 0;
}