CF954D Fight Against Traffic C++题解
题意
给定一个 \(n\) 个点,\(m\) 条边的无向联通图。你现在可以随意将两个没有连起来的点相连(只能连一条),输出有多少种连法不影响点 \(s\) 到点 \(t\) 的最短路径长度。
点的编号由 \(1\) 到 \(n\),且边权均为 \(1\)。
思路
要从 \(s\) 到 \(t\),若会影响最小值,肯定经过了刚才连上的一条边。
现称:
- \(d1_i\) 表示从 \(s \to i\) 的最短路长度;
- \(d2_i\) 表示从 \(i \to t\) 的最短路长度,同时因为这是无向图,故 \(d2_i\) 的含义 \(\Leftrightarrow t \to i\) 的最短路长度;
- 连上的边是 \(x\) 与 \(y\) 这条边。
则,从 \(s\) 到 \(t\) 有两种情况:
- \(s \to x \to y \to t\);
- \(s \to y \to x \to t\)。
由于 \(x \to y\) 的权是 \(1\),
则两种情况所对应的距离分别是:
- \(ans1 = d1_x + 1 + d2_y\)
- \(ans2 = d1_y + 1 + d2_x\)
由于 \(s \to t\) 的最短路的长度是 \(d1_t\) \((d1_t = d2_s\),都是这个最短的长度\()\)。
如果 \(\min(x1, x2) < d1_t\),说明影响了,我们要求不影响的条数,故
- 如果 \(\min(x1, x2) \geqslant d1_t\),
cnt++。
本题的大体思路总结:
- 预处理 \(d1\) 和 \(d2\);
- \(O(n^2)\) 枚举每一对 \(x\) 和 \(y\),如果 \(x \ne y \land x\) 和 \(y\) 之间没有连边,求出 \(ans1\) 和 \(ans2\),并判断是否合法;
- 输出答案。
下面简单说一下预处理 \(d1\) 和 \(d2\)。
本题没有重边,故可以邻接矩阵来存图。
直接用 bfs 算出所有点的最短路。
- 求 \(d1\) 时,队列中先插入 \(s\),接下来扩展到下一个点;
- 求 \(d2\) 时,队列中先插入 \(t\),接下来同上。
解释一下第三个最简单的样例:

如图,从 \(1 \to 5\),原图的最短路长度为 \(2\), 有以下 \(3\) 中连法使得最短路长度不变:

- 连接 \(2 \to 3\),最短路长度不变。

2. 连接 \(2 \to 4\),最短路长度不变。

3. 连接 \(3 \to 4\),最短路长度不变。
故输出 \(3\)。
代码
#include <bits/stdc++.h>
#define fr(i, l, r) for (int i = l; i <= r; ++i)
using namespace std;
int n, m, s, t, x, y, cnt, d1[1010], d2[1010], link[1010][1010];
bool vis[1010];
queue<int>q;
int min(int x, int y)
{
return x < y ? x : y;
}
void bfs(int *dis)
{
while (q.size())
{
int now = q.front(); q.pop();
fr(i, 1, n)
{
if (!link[now][i] || vis[i]) continue;
vis[i] = true, dis[i] = dis[now] + 1, q.push(i);
}
}
fr(i, 1, n) vis[i] = false; // 清空数组
while (q.size()) q.pop();
}
int main()
{
scanf("%d%d%d%d", &n, &m, &s, &t);
fr(i, 1, m) scanf("%d%d", &x, &y), link[x][y] = 1, link[y][x] = 1;
vis[s] = true, /*这里数组标 true 不能忘*/q.push(s), bfs(d1);
vis[t] = true, q.push(t), bfs(d2);
fr(i, 1, n) fr(j, i, n)
{
if (i == j || link[i][j]) continue; // 如果本来就有边或者 i = j,continue
int ans1 = d1[i] + 1 + d2[j],
ans2 = d1[j] + 1 + d2[i];
cnt += min(ans1, ans2) >= d1[t]; // 如果两种方案的最小值大于等于原本的最短路的长度,说明合法
}
printf("%d", cnt);
return 0;
}
}

浙公网安备 33010602011771号