Sightseeing Trip

https://loj.ac/problem/10072

题目描述

  给出一张图,求这幅图的最小环。

思路

  我们考虑Floyd算法的过程,dp[i][j][k]表示的是经过编号不超过k的节点,从i到j的最短路径,而用滚动数组压掉一维。所以dp[i][j]+a[j][k]+a[k][i]就是由不超过k的几点组成的经过节点k的最小环,跑一遍Floyd即可。对于输出路径,我们用pos[i][j]=k记录i到j的最短路径的经过节点,我们可以这样不断分解得到路径,就得到i到j的路径,再加上(j,k)和(k,i)两条边即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int INF=100000000;
int pos[220][220],mp[220][220],dis[220][220];
vector<int>ans;
void get_ans(int x,int y)
{
    int k=pos[x][y];
    if(k==0)return ;
    get_ans(x,k);
    ans.push_back(k);    //分割求路径 
    get_ans(k,y);
}
int main() 
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i^j)mp[i][j]=dis[i][j]=INF;
            else mp[i][j]=dis[i][j]=0;
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        mp[x][y]=mp[y][x]=min(mp[x][y],z);//防止重边 
        dis[x][y]=dis[y][x]=mp[x][y];
    }
    int sum=INF;
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=k-1;i++)
            for(int j=1;j<=k-1;j++)
                if(i^j&&dis[i][j]+mp[i][k]+mp[k][j]<sum)
                {
                    sum=dis[i][j]+mp[i][k]+mp[k][j];
                    ans.clear();
                    ans.push_back(i);
                    get_ans(i,j);            //得到i、j间的路径 
                    ans.push_back(j);
                    ans.push_back(k);
                }
        for(int i=1;i<=n;i++)
            for(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;                //记录中间节点 
                }
    }
    if(sum==INF){printf("No solution.");return 0;}
    for(int i=0;i<ans.size();i++)
        printf("%d ",ans[i]);
    return 0;
}

 

posted @ 2019-10-14 21:17  fbz  阅读(196)  评论(0编辑  收藏  举报