P6175题解

P6175(数学化语言表述,较严谨且易理解)

考虑一个环:\(a_1- >a_2 ->a_3 ->…… ->a_n -> a_1\) \((n \ge 3)\),设\(max(a_i)(1 \le i \le n) = a_k\),设\(a_k\)在环中相邻的两个点分别是\(a_v\)\(a_w\)

对于任意的几个环,如果它们的\(a_k,a_v,a_w\)都分别相等,我们就把这几个环都放入一个集合,并设这个集合为 \(S(a_k,a_v,a_w)\)

可以发现,任意一个环都属于一个集合。

\(d(x,y)\)表示\(x\)\(y\)之间直接距离(不经过其他点)。令\(f(x,y,k)\)表示x和y之间经过若干个编号\(<k\)的点得到的最短距离。

则易证,对于任意一个集合(设这个集合为\(S(a_k,a_v,a_w)\)),该集合中的最小环的长度为\(d(a_v,a_k) + d(a_k,a_w) + f(a_v,a_w,a_k)\)

因为任意一个环都属于一个集合,所以我们只要枚举所有的集合,将该集合中最小环的长度作为可能的答案进行比较,即可得到最终答案。

现在还有一个问题,那就是如何求出\(f(a_v,a_w,a_k)\)

我们可以发现\(floyd\)算法的外循环\(k\)枚举到\(a_k\)时,\(a_v,a_w\)之间的最短路径即为所求。

综上,时间复杂度\(O(n^3)\).

Code:

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>

using namespace std;

const int maxn = 105,maxm = 1e4 + 5,inf = 0x3f3f3f3f;

int n,m,vi,vj,vk,minn;
int f[maxn][maxn],v[maxn][maxn],a[maxn][maxn];
vector<int> path;

void work(int x,int y) {
if (v[x][y] == 0)
return;
int tmp = v[x][y];
work(x,tmp);
path.push_back(tmp);
work(tmp,y);
}

int main() {
scanf("%d %d",&n,&m);
memset(f,0x3f,sizeof(f));
memset(a,0x3f,sizeof(a));
for (int i=1; i<=n; i++)
f[i][i] = a[i][i] = 0;

for (int i=1; i<=m; i++) {
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
if (x > n || y > n)
continue;
a[x][y] = min(a[x][y],z);
a[y][x] = min(a[y][x],z);
f[x][y] = min(f[x][y],z);
f[y][x] = min(f[y][x],z);
}

minn = inf;

for (int k=1; k<=n; k++) {
for (int i=1; i<k; i++)
for (int j=i + 1; j<k; j++) {
if ((long long)a[i][k] + a[k][j] + f[i][j] < (long long)minn) {
minn = a[i][k] + a[k][j] + f[i][j];
path.clear();
path.push_back(i);
path.push_back(k);
path.push_back(j);
work(j,i);
}

}

for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++) {
if (i == j || j == k || i == k)
continue;

if (f[i][j] > f[i][k] + f[k][j]) {
f[i][j] = f[i][k] + f[k][j];
v[i][j] = k;
}
}
}


if (minn == inf) {
puts("No solution.");
return 0;
}

for (int i=0; i<path.size(); i++)
printf("%d ",path[i]);

return 0;
}