題解 P5683 [CSP-J2019 江西] 道路拆除
阿新 • • 發佈:2021-08-11
題解 P5683 [CSP-J2019 江西] 道路拆除
給定一個 \(n\) 個點 \(m\) 條邊的無向圖,求兩條路徑 \(1\to s_1,1 \to s_2\) ,使得兩條路徑的長度分別不大於 \(t_1,t_2\) ,且兩條路徑用到的所有邊的總數量最少。你需要輸出 \(m\) 減用到的邊數
\(1 \leq n,m \leq 3\times 10^3\) 。
考場上亂搞拿了 35pts
首先,如果直接求 \(1\) 到這兩個點的最短路,然後求這兩條最短路用到的邊的總數是不對的,因為如果公共部分多一點,可能會更優。
經過一段時間的觀察,我們容易發現:公共部分一定是一條連續的鏈,因為如果鏈的中間斷開了,那麼把更長的那一條變成更短的那一條,路徑長度變少了,公共部分變長了,肯定更優。
於是就可以列舉這個分界點 \(k\) ,這兩條路徑就被拆成了三條互不相關的路徑 \(1\to k ,k \to s_1 ,k \to s_2\) ,答案最小意味著這三條路徑都是最短路。
於是從 \(1,s_1,s_2\) \(bfs\) 三次,就可以求出這三條最短路的長度了( \(k \to s_1\) 在無向圖中的最短路徑長度等於 \(s_1\to k\) 的最短路徑長度。)
注意列舉 \(1\to k \to s_1\) 的長度 \(\leq t_1\) , \(1 \to k \to s_2\) 的長度 \(\leq t_2\) 。
程式碼如下:
#include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #include <iostream> #include <queue> using namespace std; inline int read() { int num = 0 ,f = 1; char c = getchar(); while (!isdigit(c)) f = c == '-' ? -1 : f ,c = getchar(); while (isdigit(c)) num = (num << 1) + (num << 3) + (c ^ 48) ,c = getchar(); return num * f; } const int N = 3e3 + 5 ,M = 6e3 + 5 ,INF = 0x3f3f3f3f; struct Edge { int to ,next; Edge (int to = 0 ,int next = 0) : to(to) ,next(next) {} }G[M]; int head[N] ,idx; inline void add(int u ,int v) { G[++idx] = Edge(v ,head[u]); head[u] = idx; G[++idx] = Edge(u ,head[v]); head[v] = idx; } int n ,m ,t1 ,t2 ,A ,B; inline void bfs(int s ,int dis[]) { for (int i = 1; i <= n; i++) dis[i] = INF; queue <int> q; q.push(s); dis[s] = 0; while (!q.empty()) { int now = q.front(); q.pop(); for (int i = head[now]; i ; i = G[i].next) { int v = G[i].to; if (dis[v] == INF) { dis[v] = dis[now] + 1; q.push(v); } } } } int dis1[N] ,dis2[N] ,dis3[N]; signed main() { n = read() ,m = read(); for (int i = 1; i <= m; i++) { int u = read() ,v = read(); add(u ,v); } A = read() ,t1 = read() ,B = read() ,t2 = read(); bfs(1 ,dis1); bfs(A ,dis2); bfs(B ,dis3); int ans = INF; for (int i = 1; i <= n; i++) if (dis1[i] + dis2[i] <= t1 && dis1[i] + dis3[i] <= t2) ans = min(ans ,dis1[i] + dis2[i] + dis3[i]); //這裡就算三條路徑有重複也沒關係,因為如果有重複意味著在別的分界點有更優的答案 if (ans == INF) puts("-1"); else printf("%d\n" ,m - ans); return 0; }