CF954D Fight Against Traffic C++題解
阿新 • • 發佈:2021-06-18
題意
給定一個 \(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;
}
}