【洛谷】P6175 无向图的最小环问题

题目地址:

https://www.luogu.com.cn/problem/P6175

题目描述:
给定一张无向图,求图中一个至少包含 3 3 3个点的环,环上的节点不重复,并且环上的边的长度之和最小。该问题称为无向图的最小环问题。在本题中,你需要输出最小的环的边权和。若无解,输出No solution.

输入格式:
第一行两个正整数 n , m n,m n,m表示点数和边数。接下来 m m m行,每行三个正整数 u , v , d u,v,d u,v,d,表示节点 u , v u,v u,v之间有一条长度为 d d d的边。

输出格式:
输出边权和最小的环的边权和。若无解,输出No solution.

数据范围:
对于 20 % 20\% 20%的数据, n , m ≤ 10 n,m \leq 10 n,m10
对于 60 % 60\% 60%的数据, m ≤ 100 m\leq 100 m100
对于 100 % 100\% 100%的数据, 1 ≤ n ≤ 100 1\le n\leq 100 1n100 1 ≤ m ≤ 5 × 1 0 3 1\le m\leq 5\times 10^3 1m5×103 1 ≤ d ≤ 1 0 5 1 \leq d \leq 10^5 1d105

思路是Floyd算法,参考https://blog.csdn.net/qq_46105170/article/details/113821689。Floyd算法是求点对最短路的算法,设 g [ i ] [ j ] g[i][j] g[i][j] i → j i\to j ij的最小边权(如果有平行边,取边权最小者),设 f [ k ] [ i ] [ j ] f[k][i][j] f[k][i][j]是从 i i i走到 j j j途中只经过 ≤ k \le k k编号的点的情况下的最短路径长度,那么在求出 f [ k − 1 ] f[k-1] f[k1]之后,环上点最大编号为 k k k的那些环的最小总边权就是: min ⁡ i < j { f [ k − 1 ] [ i ] [ j ] + g [ i ] [ k ] + g [ k ] [ j ] } \min_{i<j}\{f[k-1][i][j]+g[i][k]+g[k][j]\} i<jmin{f[k1][i][j]+g[i][k]+g[k][j]}枚举完所有的 k k k,即得答案。代码如下:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 110, INF = 0x3f3f3f3f;
int n, m;
// 注意,这里不能像Floyd算法里那样直接在g上操作,而要开出点对距离数组d,
// 因为边长这个信息是需要用到的
int g[N][N], d[N][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++)
      	// 防止溢出
        if (d[i][j] < INF && g[j][k] < INF && g[k][i] < INF)
          res = min(res, d[i][j] + g[j][k] + g[k][i]);
    for (int i = 1; i <= n; i++)
      for (int j = i + 1; j <= n; j++)
        d[i][j] = d[j][i] = min(d[i][j], d[i][k] + d[k][j]);
  }

  return res;
}

int main() {
  memset(g, 0x3f, sizeof g);
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) g[i][i] = 0;
  while (m--) {
    int a, b, c;
    scanf("%d%d%d", &a, &b, &c);
    g[a][b] = g[b][a] = min(g[a][b], c);
  }

  memcpy(d, g, sizeof g);

  int res = floyd();
  res < INF ? printf("%d\n", res) : puts("No solution.");
}

时间复杂度 O ( n 3 ) O(n^3) O(n3),空间 O ( n 2 ) O(n^2) O(n2)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值