补图BFS(hdu 5876)
题目大意:
给出一个图和起点S,求补图中S到其他点的最短距离。
http://acm.hdu.edu.cn/showproblem.php?pid=5876
我自己的垃圾做法:
用线段树来维护dijkstra的dis数组。每次取出dis最小的点来更新其他点。 假设x连出去的边是y1 < y2 < y3 ... < yk. 那么对于dis[1, y1 - 1] [y1 + 1, y2 - 1] [y2 + 1, y3 - 1]...这些区间做区间取min操作。 比较容易出错的的地方是每次用x更新完其他点,需要把dis[x] 设置成INF, 对于一个区间,如果最小值就是INF,说明这个区间里的点都被扩展过了,直接return,而不能对它做取min操作。 因为需要做的取min操作是O(m)的,所以总的复杂度是O(mlogn).
简单做法:
用一个set维护哪些点还没被BFS到。 每次从队列取出一个点x, 然后把set里的点分成两类,一类是和x在原图中有边相连,一类是没有边相连,把和x没有边相连的点从set中删去,加入队列。 总的复杂度是O(mlogn)
参考代码:
1 //#pragma comment(linker, "/STACK:102400000,102400000")#include <bits/stdc++.h> 2 //zoj 3496 3 #include <bits/stdc++.h> 4 using namespace std; 5 6 typedef long long ll; 7 #define X first 8 #define Y second 9 #define MAXN 200020 10 #define M 105 11 const int mod = 1e9 + 7; 12 const int INF = 1e9 + 10; 13 14 vector<int> E[MAXN]; 15 int d[MAXN]; 16 queue<int> Q; 17 set<int> st, tmp; 18 19 20 void BFS(int S, int n) 21 { 22 Q.push(S); d[S] = 0; 23 for (int i = 1; i <= n; ++i) 24 if (i != S) st.insert(i); 25 while (!Q.empty()) 26 { 27 int x = Q.front(); Q.pop(); 28 tmp.erase(tmp.begin(), tmp.end()); 29 for (auto y: E[x]) 30 { 31 if (st.find(y) != st.end()) 32 tmp.insert(y); 33 } 34 for (auto v: st) if (tmp.find(v) == tmp.end()) Q.push(v), d[v] = d[x] + 1; 35 st = tmp; 36 } 37 bool flag = false; 38 for (int i = 1; i <= n; ++i) 39 { 40 if (i == S) continue; 41 if (flag) printf(" "); 42 printf("%d", d[i]); 43 flag = true; 44 } 45 printf("\n"); 46 } 47 48 int main() 49 { 50 //freopen("input", "r", stdin); 51 //freopen("output", "w", stdout); 52 53 int T, n, m; 54 scanf("%d", &T); 55 while (T--) 56 { 57 scanf("%d %d", &n, &m); 58 for (int i = 1; i <= m; ++i) 59 { 60 int x, y; 61 scanf("%d %d", &x, &y); 62 E[x].push_back(y); 63 E[y].push_back(x); 64 } 65 int S; 66 scanf("%d", &S); 67 for (int i = 1; i <= n; ++i) d[i] = -1; 68 BFS(S, n); 69 for (int i = 1; i <= n; ++i) E[i].clear(); 70 } 71 72 return 0; 73 }
Every day is meaningful, keeping learning!