题解:P3119 [USACO15JAN] Grass Cownoisseur G
题意
给定一个含 \(n\) 个节点 \(m\) 条边的有向图,求从节点 \(1\) 出发若最多可以逆向走一条边,最多可以经过多少个节点?
分析
注意到一个强连通分量中的所有点都可以在不走反边的情况下到达,因此先对原图求强连通分量并缩点,记录每个强连通分量的大小 \(sz_u\)。建新图,插入边 \((u, v)\) 时认为它的边权是 \(sz_v\),则原问题等价于求新图在至多走一条反边的情况下,从 \(1\) 开始的最长路。
这是一个典型的 \(k\) - 限制最值路问题,考虑分层图,复制一层原图,并在插入边 \((u, v)\) 时再插入一条边 \((v, u + cnt)\)(\(cnt\) 表示强连通分量个数),表示一条反边。因为只有从第一层到第二层的边,这正好对应了“只走至多一条反边”的限制。用 spfa 跑一边最长路即可,最后答案即为 \(\max(dis_n, dis_{n + cnt})\)。
注意,若原图即为强连通图,这时应直接特判输出 \(sz_1\)。因为这时候没有边,最长路并没有运行。
代码
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int, int>;
const int N = 1e5 + 5;
int n, m;
int idx, top, cnt, dfn[N], low[N], stk[N], id[N], sz[N];
int deg[N], dis[N << 1];
bool in[N << 1];
vector<int> g[N];
vector<pii> dag[N << 1];
void scc(int u) {
dfn[u] = low[u] = ++idx;
stk[++top] = u, in[u] = true;
for (int v : g[u]) {
if (!dfn[v]) {
scc(v);
low[u] = min(low[u], low[v]);
} else if (in[v])
low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u]) {
cnt++;
int t;
do {
t = stk[top--];
in[t] = false, id[t] = cnt, sz[cnt]++;
} while (t != u);
}
return;
}
void init() {
memset(in, false, sizeof in);
memset(dis, -1, sizeof dis);
return;
}
void spfa(int s) {
queue<int> q;
in[s] = true, dis[s] = 0;
q.push(s);
while (q.size()) {
int u = q.front();
q.pop();
in[u] = false;
for (auto [v, w] : dag[u]) {
int nd = dis[u] + w;
if (nd > dis[v]) {
dis[v] = nd;
if (in[v])
continue;
q.push(v);
in[v] = true;
}
}
}
return;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
}
for (int u = 1; u <= n; u++)
if (!dfn[u])
scc(u);
if (cnt == 1) {
printf("%d\n", sz[1]);
return 0;
}
for (int u = 1; u <= n; u++) {
for (int v : g[u]) {
int x = id[u], y = id[v];
if (x == y)
continue;
dag[x].push_back({y, sz[y]}), dag[x + cnt].push_back({y + cnt, sz[y]});
// 插入原边并复制到第二层
dag[y].push_back({x + cnt, sz[x]});
// 插入跨层边(反边)
}
}
init(); // spfa 和 tarjan 共用了一个 in 数组,应该清空
int s = id[1]; // 注意是从 1 所在 SCC 跑 spfa 而不是 1 这个节点
spfa(s);
printf("%d\n", max(dis[s], dis[s + cnt]));
return 0;
}

浙公网安备 33010602011771号