日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU 2833 WuKong

發(fā)布時間:2025/3/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU 2833 WuKong 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

傳送門

求兩條最短路最多重疊的點數(shù)。
給一個無向圖,再給兩對起點終點,每一對起點終點之間都可能有多條最短的路,設(shè)s1和t1的最短路是r1,s2和t2的最短路是r2,求r1和r2最多能相互重疊多少個點。

這道題思想很巧妙,涉及了dp的思想。首先想明白一個問題,兩條最短路最多的重疊部分必然是連續(xù)的,不可能有兩段或更多段分散的重疊部分。為什么?反證法,若有的話,則某兩段重疊部分之間的各自的分散部分一定可以都采用更小的那段分散部分。

建立一個數(shù)組cnt[][]記錄全圖的兩點之間的最短路最多可以有多少條邊,使用floyd算法,在g[i][k]+g[k][j] < g[i][j]和g[i][k]+g[k][j] == g[i][j]兩種情況下對cnt[i][j]進行計算。然而,還要對cnt[][]數(shù)組進行初始化,很直接的想法就是初始邊的兩點設(shè)為1,沒有邊的兩點為0。但是,這里有一個坑!輸入數(shù)據(jù)中實錘有自環(huán)! 自環(huán)意味著cnt[x][x]也被設(shè)為了1,但是這是不符合定義的,除非你這個自環(huán)的權(quán)值是非正數(shù),但是根據(jù)題意,權(quán)值的實際意義是路的長度,都是正值。(如果是非正的話這題也就GG了,有可達的零環(huán)意味著可以在這個零環(huán)上走到死,使得重疊的點數(shù)無窮大,有可達的負環(huán)意味著你連最短路都求不出來)
說這么多就很簡單,當a,b兩點之間有邊時,要在cnt[a][b] = cnt[b][a] = 1之前加上條件a != b。

接下來提一下上述情況具體運行到哪里出了問題。
答案:當k==i或者k==j時,在floyd里的cnt[i][j] < cnt[i][k] + cnt[k][j]這個條件下引發(fā)了錯誤判斷,繼而計算了錯誤值。(想一想我在這個里面提過的三個情況)
證據(jù):把輸入邊時的a!=b條件去掉,在floyd的此處加上條件&&(k!=i)&&(k!=j),也AC了。

最后,枚舉每兩個點,判斷這兩點之間的最短路能不能同時成為s1,t1和s2,t2的最短路的一部分,這個判斷的寫法很巧妙,和cnt[][]沒關(guān)系。若可以的話我們再拿這兩點cnt[][]的值更新ans。(雖然這兩點之間可能有多條最短路,但是這些最短路都是首尾一致的,可以隨意替換,于是我們都拿cnt[][]最大的那個當作子路)

(4月9日更新:其實這個題只要在floyd里面讓i,j,k各不相等就行了)

#include <cstdio> #include <iostream> #include <algorithm> #include <vector> #include <cstring> #include <string> #include <queue> using namespace std;const int INF = 1e9; const int MAXN = 301; int N, M;int g[MAXN][MAXN]; int cnt[MAXN][MAXN]; // 兩點的所有最短路上最多有幾條邊 int ans;void init() {for (int i = 1; i <= N; i++){for (int j = i; j <= N; j++){if (i == j) g[i][j] = 0;else g[i][j] = g[j][i] = INF;}}memset(cnt, 0, sizeof cnt);ans = -1; }int main() {int a, b, c, d;for (; ~scanf("%d%d", &N, &M);){if (!N && !M) break;init();for (int i = 0; i < M; i++){scanf("%d%d%d", &a, &b, &c);g[a][b] = g[b][a] = min(g[a][b], c);if (a != b) // 如果來 X X Y 的數(shù)據(jù)怎么辦? (自環(huán))(Y肯定大于0)cnt[a][b] = cnt[b][a] = 1; // 必須始終讓cnt[x][x]=0,無論有沒有自環(huán),因為永遠都不能走這個自環(huán)! }scanf("%d%d%d%d", &a, &b, &c, &d);for (int k = 1; k <= N; k++){for (int i = 1; i <= N; i++){for (int j = 1; j <= N; j++){if (g[i][k] != INF && g[k][j] != INF && g[i][k] + g[k][j] < g[i][j]){g[i][j] = g[i][k] + g[k][j];cnt[i][j] = cnt[i][k] + cnt[k][j];}else if (g[i][k] + g[k][j] == g[i][j] && cnt[i][j] < cnt[i][k] + cnt[k][j]){cnt[i][j] = cnt[i][k] + cnt[k][j];}}}}for (int i = 1; i <= N; i++){for (int j = 1; j <= N; j++){if (cnt[i][j] > ans){if (g[a][b] == g[a][i] + g[i][j] + g[j][b] && g[c][d] == g[c][i] + g[i][j] + g[j][d]){ // 表示i,j的最短路至少可以是a,b其中一條最短路的子路ans = cnt[i][j];}}}}printf("%d\n", ans + 1); // 可以證明兩條最短路的重疊部分一定是連續(xù)的,所以再加1等于重疊的點數(shù)}return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/CrossingOver/p/10704843.html

總結(jié)

以上是生活随笔為你收集整理的HDU 2833 WuKong的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。