URAL 1004 Sightseeing Trip 无向图最小环

题目:

https://vjudge.net/problem/14074

题意:

给定一个有n个点的无向图,有m条无向边,求图中一个至少包含三个点的环,并输出环上的点,有多解任意输出一个即可,没有这样的环则输出No solution.

思路:

可以用floyd算法求解最小环,然后记录路径输出即可。
关于记录路径:定义pro[i][j]为点i到点j路径上的倒数第二个点,倒数第一个自然是j,初始化pro[i][j]为i。当dis[i][j] > dis[i][k] + dis[k][j]成立时,意味着点i到点j的路径要改成点i到点k再到点j,而dis[k][j]已知,意味着pro[k][j]已知,即点k到点j的路径已知,所以此时应该把pro[k][j]存到pro[i][j]中,即pro[i][j] = pro[k][j]

#include <bits/stdc++.h>
using namespace std;

const int N = 110, INF = 1<<28;
int n, m, tot;
int g[N][N], dis[N][N], pro[N][N], path[N];

int floyd()
{
    int res = INF;
    for(int k = 1; k <= n; k++)
    {
        for(int i = 1; i < k; i++)
            for(int j = i+1; j < k; j++)
            {
                int tmp = dis[i][j] + g[i][k] + g[k][j];
                if(res > tmp)
                {
                    res = tmp;
                    tot = 0;
                    int p = j;
                    while(p != i)
                    {
                        path[tot++] = p;
                        p = pro[i][p];
                    }
                    path[tot++] = i, 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];
                    pro[i][j] = pro[k][j];
                }
    }
    return res;
}
int main()
{
    while(scanf("%d", &n), n != -1)
    {
        scanf("%d", &m);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
            {
                if(i == j) g[i][j] = dis[i][j] = 0;
                else g[i][j] = dis[i][j] = INF;
                pro[i][j] = i;
            }
        for(int i = 1; i <= m; i++)
        {
            int v, u, c;
            scanf("%d%d%d", &v, &u, &c);
            g[v][u] = g[u][v] = dis[v][u] = dis[u][v] = min(g[v][u], c);
        }
        int res = floyd();
        if(res == INF) printf("No solution.\n");
        else
        {
            for(int i = tot-1; i >= 0; i--) printf("%d%c", path[i], i == 0 ? '\n' : ' ');
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值