题解 P1841 【[JSOI2007]重要的城市】
怎么全都是Floyd...提供一个不一样的思路(可能蒟蒻脑回路清奇,第一思路就这个...)
一个城市x重要,当且仅当去掉它之后可以让s->t的最短路变化(s != t != x)。因为本题的n很小,我们可以枚举n作为s。
当确定s之后,以s为起点跑一次最短路,然后把所有在最短路上的边加入一个新图中。具体做法是:对于一条边,如果它起点处的最短路加上边权等于终点处的最短路,那么就把它加入新图中。
这个新图有一个很好的性质:它是一个DAG。原因很简单,最短路上没环= =。注意到这个最短路DAG记录了s为起点到所有点的最短路。
枚举1~n的每个点。如果存在边x->y,并且y的入度为1,那么删掉x之后y的入度会变成0,显然无法从s到达,即删掉x之后破坏了一些点的最短路。x就是一个关键点。
时间复杂度:枚举
#include <bits/stdc++.h>
using namespace std;
inline int rd() {
int a = 1, b = 0; char c = getchar();
while (!isdigit(c)) a = c == '-' ? 0 : 1, c = getchar();
while (isdigit(c)) b = b * 10 + c - '0', c = getchar();
return a ? b : -b;
}
const int N = 500, M = N * N;
struct Graph {
int from, to, nxt, c;
} g[M * 2];
int head[N], tot;
void addedge(int x, int y, int c) {
g[++tot].to = y, g[tot].from = x, g[tot].c = c,
g[tot].nxt = head[x], head[x] = tot;
}
int n, m;
priority_queue<pair<int, int> > que;
int dis[N], in[N];
bool vis[N], important[N], mark[M];
void solve(int s) {
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[s] = 0;
que.push(make_pair(0, s));
while (!que.empty()) {
int x = que.top().second;
que.pop();
if (!vis[x]) {
vis[x] = true;
for (int i = head[x]; i; i = g[i].nxt) {
int y = g[i].to;
if (dis[y] > dis[x] + g[i].c) {
dis[y] = dis[x] + g[i].c;
que.push(make_pair(-dis[y], y));
}
}
}
}
memset(mark, 0, sizeof(mark));
memset(in, 0, sizeof(in));
for (int i = 1; i <= tot; ++i) {
if (dis[g[i].from] + g[i].c == dis[g[i].to]) {
mark[i] = true;
++in[g[i].to];
}
}
for (int i = 1; i <= tot; ++i)
if (mark[i] && in[g[i].to] == 1 && g[i].from != s)
important[g[i].from] = true;
}
int main() {
n = rd(), m = rd();
for (int i = 1; i <= m; ++i) {
int x = rd(), y = rd(), c = rd();
addedge(x, y, c), addedge(y, x, c);
}
for (int i = 1; i <= n; ++i)
solve(i);
bool ok = false;
for (int i = 1; i <= n; ++i)
if (important[i]) {
cout << i << " ";
ok = true;
}
if (!ok) cout << "No important cities.";
cout << endl;
return 0;
}