P2941 [USACO09FEB]Surround the Islands S 題解
阿新 • • 發佈:2020-12-02
1.題目大意
這道題我認為配不上藍題,我覺得這不科學,這道題的神奇之處在於它的題面描述十分的神奇。
中文翻譯可能有一些問題,我們看看英文翻譯,它要求我們在去到一個島後立馬回到原來的島。這不就是一個菊花圖嗎??
2.程式碼實現
我們先用並查集來把環縮掉,然後直接列舉以每個節點為中心的菊花圖,記得把答案乘\(2\)(我們要去一趟,回來一趟,共兩趟),時間複雜度\(O(n^2)\)
有些大佬用Tarjan縮點,這樣未免太麻煩,這個圖是一個不聯通的,每兩個環之間沒有其他的邊連線!!!
#include <bits/stdc++.h> using namespace std; int n, fa[505]; int dis[505][505]; int ans = INT_MAX, tot; int opt[505]; int getfa(int x) { //並查集的核心操作 if(x == fa[x]) return x; return fa[x] = getfa(fa[x]); //路徑壓縮優化 } int main() { cin >> n; memset(dis, 127, sizeof(dis)); //初始化兩點之間的距離 for (int i = 1; i <= n ; i ++) fa[i] = i; //並查集初始化 for (int i = 1; i <= n ; i ++) { int x, y; scanf("%d%d", &x, &y); int fx = getfa(x), fy = getfa(y); if (fx != fy) //如果在同一個並查集裡面,說明這條線段是那個島嶼的一部分 fa[fx] = fy; } for (int i = 1; i <= n ; i ++) //統計總共有多少島嶼,並把它編號 if (fa[i] == i) opt[++tot] = i; for (int i = 1; i <= n ; i ++) { int xxx = getfa(i); for (int j = 1; j <= n ; j ++) { int yyy = getfa(j); int x; scanf("%d", &x); dis[xxx][yyy] = min(dis[xxx][yyy], x);//在輸入的時候計算兩個島嶼之間的最短路徑 //注意,我們算的不是最短路,而是兩個島嶼之間的直接路徑的長度 } } for (int i = 1; i <= tot; i ++) { //以每個島為菊花圖的中心 int sum = 0; for (int j = 1; j <= tot; j ++) {//列舉其他島 if (i == j) continue; sum += dis[opt[i]][opt[j]]; } ans = min(ans, sum); } cout << (ans << 1) << endl; //輸出要乘二!!! return 0; }
3.注意事項
這個程式碼中有幾個地方需要注意,一個是在答案輸出的時候時候要乘二,因為要往返一次,第二個是並查集要記得初始化!!!!(我調這個花了半個小時,我太菜了)。
完結撒花!!