EOJ 2165 寻找航海路线 非严格次小生成树

题目描述

茫茫大海上有许多小岛,为了避免不可预知的危险,人们只能在两岛之间直线行船。先辈们找到了一个岛之间的最佳航海路线,所谓最佳航海路线,就是能够连接所有的岛且路线长度总和最小。但随着航海业的日益发展,这条路线变得日益拥挤,于是海运局聘请你寻找另外一个尽可能佳的路线,所经过的小岛与原路线不完全相同就可。

输入格式

有多组测试数据。第一行两个整数 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 2

output

4 4
4 -1

思路:题目要求输出的答案其实是最小生成树的长度以及(非严格)次小生成树长度。次小生成树是在最小生成树的基础上,遍历所有未被选中的边,尝试着将其加入最小生成树,并删去由此产生的环中除了新加入的这条边外最长的那条边(即留下的边都是最短的那些,保证新的树长度尽可能小),选取遍历结果中长度最小的树,即为次小生成树,由于这样产生的树长度可能与最小生成树相同,因此这种次小生成树是非严格的,但题目描述的正是这种非严格的次小生成树。次小生成树算法可以由Prim算法改良,需要额外的数组记录未被选中的边集,以及每两个点之间最长的边(用动态规划思想实现),代码如下:

 

#include 
#include 
#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]>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>u>>v>>w;
            cost[u][v] = w;
            cost[v][u] = w;
        }
        MST = Prim(N);
        SMT = second_st(N, MST);
        cout<

 

你可能感兴趣的:(EOJ)