题目链接

Sightseeing trip

题目描述

There is a travel agency in Adelton town on Zanzibar island. It has decided to offer its clients, besides many other attractions, sightseeing the town. To earn as much as possible from this attraction, the agency has accepted a shrewd decision: it is necessary to find the shortest route which begins and ends at the same place. Your task is to write a program which finds such a route.

In the town there are N crossing points numbered from $1$ to $N$ and $M$ two-way roads numbered from $1$ to $M$. Two crossing points can be connected by multiple roads, but no road connects a crossing point with itself. Each sightseeing route is a sequence of road numbers $y_1$, ..., $y_k, k>2$. The road $y_i$ ($1 \le i \le k-1$) connects crossing points $x_i$ and $x_{i+1}$, the road $y_k$ connects crossing points $x_k$ and $x_1$. All the numbers $x_1$,...,$x_k$ should be different.The length of the sightseeing route is the sum of the lengths of all roads on the sightseeing route, $i.e.\ L$($y_1$)$+L$($y_2$)$+...+L$($y_k$) where $L$($y_i$) is the length of the road $y_i$ ($1 \le i \le k$). Your program has to find such a sightseeing route, the length of which is minimal, or to specify that it is not possible,because there is no sightseeing route in the town.

输入格式

The first line of input contains two positive integers: the number of crossing points $N \le 100$ and the number of roads $M \le 10000$. Each of the next $M$ lines describes one road. It contains $3$ positive integers: the number of its first crossing point, the number of the second one, and the length of the road (a positive integer less than $500$).

输出格式

There is only one line in output. It contains either a string '$No solution.$' in case there isn't any sightseeing route, or it contains the numbers of all crossing points on the shortest sightseeing route in the order how to pass them ($i.e.$ the numbers $x_1$ to $x_k$ from our definition of a sightseeing route), separated by single spaces. If there are multiple sightseeing routes of the minimal length, you can output any one of them.

样例输入

5 7
1 4 1
1 3 300
3 1 10
1 2 16
2 3 100
2 5 15
5 3 20

样例输出

1 3 5 2

题解

题意:给定一个无向图,求最短的环,顺序输出环上的每个点。
如果直接暴力dfs找环,那么肯定会$T$的。
我们考虑到最小环肯定是由两个节点的最短路和次短路组成。
那么我们马上就想到了伟大的Floyd,只需要优良的$O$($n^3$)。
假设我们用$s[j][i]$存$j$到$i$的最短路。
我们只要在每次更新之前把当前将要更新的路径(最短路)和$s[j][i]$(次短路)加起来和答案取$min$就好了。
因为最后一次更新之后$s[j][i]$就是最短路了,所以更新之前是次短路。
那么我们接下来就有这么一个问题了,怎么求路径。
我们这里用$up[j][i]$表示从$j$到$i$的最短路,$i$的父亲是谁。
那么我们每次更新的时候把$up$也更新上就好了。
上代码:

#include<cstdio>
#include<string.h>
using namespace std;
int n,m,x,y,w;
int to[109][109];
int s[109][109];
int up[109][109];
int anss[109],ls,ans=-1;
void dfs(){
    for(int k=1;k<=n;k++){
        for(int j=1;j<k;j++){
            for(int i=j+1;i<k;i++){
                if(s[j][i]==-1 || to[j][k]==-1 || to[k][i]==-1) continue;
                if(ans==-1 || ans>s[j][i]+to[j][k]+to[k][i]){
                    ans=s[j][i]+to[j][k]+to[k][i];
                    ls=0;
                    int u=i;
                    while(u!=j){
                        anss[++ls]=u;
                        u=up[j][u];
                    }
                    anss[++ls]=j;
                    anss[++ls]=k;//把当前最小环存到anss数组里
                }
            }
        }
        for(int j=1;j<=n;j++)
            for(int i=1;i<=n;i++){
                if(s[j][k]==-1 || s[k][i]==-1) continue;
                if(s[j][i]==-1 || s[j][i]>s[j][k]+s[k][i]){
                    s[j][i]=s[j][k]+s[k][i];
                    up[j][i]=up[k][i];
                }
            }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    memset(to,-1,sizeof(to));
    memset(s,-1,sizeof(s));
    for(int j=1;j<=m;j++){
        scanf("%d%d%d",&x,&y,&w);
        if(to[x][y]==-1 || to[x][y]>w) to[x][y]=to[y][x]=w;//注意重边
    }
    for(int j=1;j<=n;j++)
        for(int i=1;i<=n;i++){
            s[j][i]=to[j][i];
            up[j][i]=j;
        }
    dfs();
    if(ans==-1){
        printf("No solution.");
        return 0;
    }
    for(int j=1;j<=ls;j++)
        printf("%d ",anss[j]);
    return 0;
}