URAL - 1004 Sightseeing Trip(最小环)

Sightseeing Trip

题目链接:Sightseeing Trip

题意:给你一个无向有环图,有n个点,m条边(可能有重边),问图中的最小环是多少,打印出最小环

思路:
一种方法是:对于每一个(u,v),去掉(u,v)这条边,然后最短路跑一遍计算出u到v的最短距离s,s+dis[u][v]就是环的长度,遍历找出最小环即可

另一种方法是:在用Floyd()松弛之前,对于当前的每一个k,都可以看成存在以k为起点和终点的环(k点为环中最大的点),并且环中的所有边都没有被k松弛过。
那么对于每一个k点,只需要先寻找k的最小环再松弛即可

代码:

#include
#include
#include
using namespace std;

const int inf=1e8;//注意inf不能过大,否则会爆int
const int maxn=105;
int dis[maxn][maxn],mp[maxn][maxn],path[maxn],pre[maxn][maxn];//dis表示松弛的图,mp表示原图,pre记录前面的点
int n,m,minx,tot;

void Floyd()
{
    minx=inf;
    for(int k=1; k<=n; ++k)
    {
        for(int i=1; ifor(int j=i+1; jif(dis[i][j]+mp[i][k]+mp[k][j]0;
                    int tmp=j;
                    path[tot++]=j;
                    while(tmp!=i)
                    {
                        tmp=pre[i][tmp];
                        path[tot++]=tmp;
                    }
                    path[tot++]=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];
                    pre[i][j]=pre[k][j];//注意pre的写法
                }
    }
}

void init()
{
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=n; ++j)
        {
            dis[i][j]=mp[i][j]=inf;
            pre[i][j]=i;
        }
}

int main()
{
    while(scanf("%d",&n)&&(n+1))
    {
        init();
        scanf("%d",&m);
        int u,v,w;
        for(int i=1; i<=m; ++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            if(wif(minx==inf)
            printf("No solution.\n");
        else
        {
            for(int i=0; i1; ++i)
                printf("%d ",path[i]);
            printf("%d\n",path[tot-1]);
        }
    }
    return 0;
}

你可能感兴趣的:(最短路径)