poj 1734 Sightseeing trip

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 7827 Accepted: 2956 Special Judge

Description
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<=i<=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<=i<=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.

Input
The first line of input contains two positive integers: the number of crossing points N<=100 and the number of roads M<=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).

Output
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.

Sample Input

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

Sample Output

1 3 5 2

解题思路

lyd书上的题,大意是找一个无向图里最小的环,因为n很小,考虑floyd。
floyd的过程是找到i,j中间的某一点k,用dis[i][k]+dis[k][j]来更新dis[i][j] 。
我们重新定义dis[i][j]为编号不超过k的最短路长度,我们每次选取k两边的点i,j,看是否dis[i][j]+a[i][k]+a[k][j]最小,为什么不可能是a[i][k]+a[k][j]作为dis[i][j] 呢,因为此时的dis[i][j]还没有用此时枚举的k来更新,如果最小就记录答案。边寻找最小环是也要边更新dis的值。
记录环非常的巧妙,每次更新dis[i][j] 的值时要记录一个pos[i][j] = k,意思是i,j这两个点是由中间的点k来更新,这样的话就用递归的方法来更新。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define LL long long

using namespace std;
const int MAXN = 105;
const int inf = 0x3f3f3f3f;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
    return x*f;
}

int n,m,ans=inf;
int a[MAXN][MAXN];
int pos[MAXN][MAXN];
int dis[MAXN][MAXN];
vector<int> path;

inline void get_path(int x,int y){
    if(!pos[x][y]) return;
    get_path(x,pos[x][y]); //相当于继续寻找i,k之间由哪个点更新。
    path.push_back(pos[x][y]);
    get_path(pos[x][y],y);  //这时的y是上一次的pos[x][y]
}

inline void floyd(){
    for(register int k=1;k<=n;k++){
        for(register int i=1;i<k;i++)
            for(register int j=i+1;j<k;j++)
                if((LL)dis[i][j]+a[i][k]+a[k][j]<ans){  //要开LL
                    ans=dis[i][j]+a[i][k]+a[k][j];
                    path.clear();
                    path.push_back(i);
                    get_path(i,j);
                    path.push_back(j);
                    path.push_back(k);
                }
        for(register int i=1;i<=n;i++)  //更新dis值
            for(register int j=1;j<=n;j++)
                if(dis[i][j]>dis[i][k]+dis[k][j]){
                    dis[i][j]=dis[i][k]+dis[k][j];
                    pos[i][j]=k;
                }
    }

}

int main(){
    memset(a,0x3f,sizeof(a));
    n=rd();m=rd();
    for(register int i=1;i<=n;i++) a[i][i]=0;
    for(register int i=1;i<=m;i++){
        int x=rd(),y=rd(),z=rd();
        a[x][y]=a[y][x]=min(a[x][y],z);
    }
    memcpy(dis,a,sizeof(a));
    floyd();
    if(ans==inf) {
        puts("No solution.");
        return 0;
    }
    for(register int i=0;i<path.size();i++)
        printf("%d ",path[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/9676967.html