0%

P6175 无向图的最小环问题

P6175.无向图的最小环问题

题目描述:

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

数据范围:

$1\le n \le 100, 1\le m \le 5\times 10^3,1\le d \le 10^5$

题解:

如果用环上点的最大编号对环进行标识,那么刚好对应floyd算法。floyd算法的最外层循环枚举的是中转点,可以把它作为最大的点。floyd保证了最外层遍历到 $k$ 时,已经求出以 $[0,k-1]$ 为中间点的最短路径。假设在某个环中最大编号为 $L$ ,那么在floyd算法外层遍历到 $L$ 时,已经得到 $x,y$ 之间不包含 $L$ 的最短路。这时,如果加上 $(L,x)(L,y)$ 就可以得到一个经过 $x,y,L$ 的环。求最小环的话,每次更新最小值即可。

注意枚举环的循环,需要枚举 $[0,k-1]$ 中的 $x,y$ ,然后因为需要求至少包含3个点的环,所以 $x\ne y$ .这个地方相加可能会溢出,需要注意不能使用0x3f。也可以全转成 long long

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using namespace std;
using namespace FAST_IO;
const ll mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INF_LL = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-5;
const int maxn = 1e2 + 10;
const int maxm = 1e5 + 10;
int t, n, m, k;
int g[maxn][maxn];
int dp[maxn][maxn];
int ans;
void solve()
{
ans = INF;
for (int k = 1; k <= n; ++k)
{
for (int i = 1; i < k; ++i)
{
for (int j = 1; j < k; ++j)
{
if (i != j)
ans = min(1ll * ans, 1ll * dp[i][j] + g[i][k] + g[k][j]); // 可能会溢出
}
}
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
dp[j][i] = dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
}
}
}
}

int main()
{
// #define COMP_DATA
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
read(n, m);
memset(g, 0x3f, sizeof(g));
memset(dp, 0x3f, sizeof(dp));
for (int i = 1, u, v, w; i <= m; ++i)
{
read(u, v, w);
g[u][v] = g[v][u] = min(w, g[u][v]);
dp[u][v] = dp[v][u] = g[u][v];
}
solve();
if (ans == INF)
cout << "No solution." << endl;
else
cout << ans << endl;
return 0;
}