HDU 5876 Sparse Graph(補圖上BFS)

題目連接:http://acm.hdu.edu.cn/showproblem.php?pid=5876php

題意:ios

  有一個 n 個點無向圖,再給你 m 對頂點, 表明着這 m 對頂點之間沒有邊, 除此以外每兩個點之間都有一條邊, 且權值爲 1.而後還有一個源點 S, 讓你計算源點到其餘各點之間的最短距離,若是不存在則輸出 -1.也就是說讓你在所給的圖的補圖上求源點到其餘各點的最短路徑.算法

思路:數組

  補圖上求最短路徑算是比較經典的題.在這裏所求的最短路其實並不須要用到 dijkstra 之類的算法,因爲每條邊之間的距離都爲 1,每條邊的權值同樣.那麼就能夠想到這個作法:優化

  步驟1:根據題意建圖.而後創建一個隊列,把源點 S 壓入隊列,其餘的各個點存到另外一個集合 V 裏, 並創建一個數組來存儲源點到其餘各點的最短距離,初始化爲 -1, dis[S] = 0.spa

  步驟2:從隊列首部取出一個節點 v,訪問全部與節點 v 不相鄰的節點 u,把 u 壓入到隊列尾部, 並從集合 V 中把 u 除去, 更新dis[u] = dis[v] + 1.code

  步驟3:反覆重複步驟 2, 直到隊列爲空.以後 dis 數組裏保存的就是答案.blog

  解決了怎麼作以後,尚未完,因爲題目給的點數很是大,因此還須要優化下時間.這裏比較費時間的就是步驟 2 中的找不相鄰的點.這裏就能夠用 STL 中的 set 來維護集合 V, 也就是未被訪問到的點. 初始化 set1 中爲全部點(除去源點 S), 當訪問的點 v 時, 在 set1 中除去與點 v 相鄰的點 u, 並加入到 set2 中,那麼 set1 中剩下的點就是全部與點 v 不相鄰的點, 依次遍歷壓入隊列. 以後再把 set2 拷貝到 set1, 那麼 set1 就是剩下的未被訪問到的點,如此反覆下去.能夠看到,對於每條邊只訪問一次.每一個點也只進一次隊列.因此總的時間複雜度爲 O(n * m),能夠達到要求了.隊列

notes:創建 無向圖 的時候每條邊要存兩次. 因此數組的大小必定是原題所給的邊數的兩倍! 兩倍! 兩倍!順便求一個用鏈表實現的代碼,本身用鏈表沒寫出來.(我好菜啊.jpgget

代碼:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <queue>
 4 #include <set>
 5 #include <cstring>
 6 #include <algorithm>
 7 
 8 using namespace std;
 9 typedef long long LL;
10 
11 const int MAXN = 200000;
12 const int MAXE = 20000;
13 int n, m, T, S;
14 int dis[MAXN + 3];//保存最終的最短距離
15 
16 int head[MAXN + 3], len; //鏈式前向星
17 struct NODE {int to; int next; };
18 NODE edge[2 * MAXE + 3];
19 
20 void addedge(int u, int v) { //鏈式前向星加邊
21     edge[len].to = v;
22     edge[len].next = head[u];
23     head[u] = len++;
24 }
25 
26 void BFS() { //從起點開始BFS
27     memset(dis, -1, sizeof(dis));
28     queue <int> Qu;
29     Qu.push(S); dis[S] = 0; //起點初始化
30     set<int> unsed, hep;    //用來維護還沒有被訪問的點
31     for(int i = 1; i <= n; i++) unsed.insert(i);
32     unsed.erase(S);
33     while( !Qu.empty() ) {
34         int tp = Qu.front(); Qu.pop();
35         for(int k = head[tp]; k != -1; k = edge[k].next) { //從 unsed 中除去和當前拓展節點相鄰的點,同時加入到臨時輔助的集合中
36             if(unsed.find(edge[k].to) != unsed.end()) {
37                 unsed.erase(edge[k].to);
38                 hep.insert(edge[k].to);
39             }
40         }
41         for(set<int>::iterator it = unsed.begin(); it != unsed.end(); it++) {// unsed 暫時保存的是和當前拓展節點不相鄰的點
42             Qu.push(*it);
43             dis[*it] = dis[tp] + 1;
44         }
45         hep.swap(unsed), hep.clear();//從輔助集合中 copy 剩下的未被訪問到的點.
46     }
47 }
48 
49 int main() {
50     scanf("%d", &T);
51     while(T--) {
52         memset(head, -1, sizeof(head));
53         scanf("%d%d", &n, &m);
54         int u, v; len = 0;
55         for(int i = 0, len = 0; i < m; i++) {
56             scanf("%d%d", &u, &v);
57             addedge(u, v); addedge(v, u);
58         }
59         scanf("%d", &S);
60         BFS();
61         for(int i = 1, j = 0; i <= n; i++) if(i != S) printf("%d%c", dis[i], " \n"[++j == n - 1]);
62     }
63     return 0;
64 }
相關文章
相關標籤/搜索