题目链接:
由题意:只需要破坏所有最短路中共同的点,即破坏了其它点到另外点的距离。
如何求破环所有最短路中共同的点呢???
d[i][j]表示点 i 到点 j 的距离:
f[i][j]表示从点 i 到点 j 最短距离的方案数:
则假设从 i 到 j 的最短距离为点 k 。
则满足:
d[i][j] == d[i][k] + d[k][j] && f[i][j] == f[i][k] * f[k][j]。
说明所有最短路的共同点是点 k 。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 210, INF = 0x3f3f3f3f;
int n, m;
int d[N][N];
int f[N][N];
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
if (i != j) d[i][j] = INF;
for (int i = 0; i < m; i ++ )
{
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
d[a][b] = d[b][a] = min(c, d[a][b]);
f[a][b] = f[b][a] = 1;
}
for (int k = 1; k <= n; k ++ )
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
if (d[i][j] > d[i][k] + d[k][j])
{
d[i][j] = d[i][k] + d[k][j];
f[i][j] = f[i][k] * f[k][j];
}
else if (d[i][j] == d[i][k] + d[k][j])
f[i][j] += f[i][k] * f[k][j];
for (int i = 1; i <= n; i ++ ) d[i][i] = INF;
bool flag = false;
for (int k = 1; k <= n; k ++ )
{
bool is_print = false;//防止重复输出同一个点
for (int i = 1; i <= n; i ++ )
{
for (int j = 1; j <= n; j ++ )
if (d[i][j] == d[i][k] + d[k][j] && f[i][j] == f[i][k] * f[k][j])
{
printf("%d ", k);
flag = true;
is_print = true;
break;
}
if (is_print) break;
}
}
if (!flag) puts("No important cities.");
return 0;
}