HDU 5876 Sparse Graph(补图上BFS)

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

题意:

  有一个 n 个点无向图,再给你 m 对顶点, 代表着这 m 对顶点之间没有边, 除此之外每两个点之间都有一条边, 且权值为 1.然后还有一个源点 S, 让你计算源点到其他各点之间的最短距离,如果不存在则输出 -1.也就是说让你在所给的图的补图上求源点到其他各点的最短路径.

思路:

  补图上求最短路径算是比较经典的题.在这里所求的最短路其实并不需要用到 dijkstra 之类的算法,由于每条边之间的距离都为 1,每条边的权值一样.那么就可以想到这个做法:

  步骤1:根据题意建图.然后建立一个队列,把源点 S 压入队列,其他的各个点存到另一个集合 V 里, 并建立一个数组来存储源点到其他各点的最短距离,初始化为 -1, dis[S] = 0.

  步骤2:从队列首部取出一个节点 v,访问所有与节点 v 不相邻的节点 u,把 u 压入到队列尾部, 并从集合 V 中把 u 除去, 更新dis[u] = dis[v] + 1.

  步骤3:反复重复步骤 2, 直到队列为空.之后 dis 数组里就保存的就是答案.

  解决了怎么做之后,还没有完,由于题目给的点数非常大,所以还需要优化下时间.这里比较费时间的就是步骤 2 中的找不相邻的点.这里就可以用 STL 中的 set 来维护集合 V, 也就是未被访问到的点. 初始化 set1 中为所有点(除去源点 S), 当访问的点 v 时, 在 set1 中除去与点 v 相邻的点 u, 并加入到 set2 中,那么 set1 中剩下的点就是所有与点 v 不相邻的点, 依次遍历压入队列. 之后再把 set2 拷贝到 set1, 那么 set1 就是剩下的未被访问到的点,如此反复下去.可以看到,对于每条边只访问一次.每个点也只进一次队列.所以总的时间复杂度为 O(n * m),可以达到要求了.

notes:建立 无向图 的时候每条边要存两次. 所以数组的大小一定是原题所给的边数的两倍! 两倍! 两倍!

代码:

 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 }
时间: 2024-08-25 13:16:37

HDU 5876 Sparse Graph(补图上BFS)的相关文章

hdu 5876 Sparse Graph 无权图bfs求最短路

Sparse Graph Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Problem Description In graph theory, the complement of a graph G is a graph H on the same vertices such that two distinct vertices of H are adjacent if

HDU 5876 Sparse Graph BFS 最短路

Sparse Graph Problem Description In graph theory, the complement of a graph G is a graph H on the same vertices such that two distinct vertices of H are adjacent if and only if they are notadjacent in G. Now you are given an undirected graph G of N n

HDU 5876 Sparse Graph

题目:Sparse Graph 链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5876 题意:给出一个图(V<=20万,E<=2万),要求先化为补图(每两个点,原本有边删去边,原本没边添加边),然后问指定点S到其他每个点的最短距离. 思路: 普通的广搜应该解决不了...O(n*m)太大,不会很难,比赛时没做出来有点可惜,当知道过了也进不了时,就安慰了许多. 变化一下思路,从起点出发,因为原本边<=2万,那么大部分的点都已经可以到达了

HDU 5876 Sparse Graph(补图中求最短路)

http://acm.hdu.edu.cn/showproblem.php?pid=5876 题意: 在补图中求s到其余各个点的最短路. 思路:因为这道题目每条边的距离都是1,所以可以直接用bfs来做. 处理的方法是开两个集合,一个存储当前顶点可以到达的点,另一个存储当前顶点不能到达的点.如果可以到达,那肯定由该顶点到达是最短的,如果不能,那就留着下一次再判. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstr

HDU 5867 Sparse Graph (2016年大连网络赛 I bfs+补图)

题意:给你n个点m条边形成一个无向图,问你求出给定点在此图的补图上到每个点距离的最小值,每条边距离为1 补图:完全图减去原图 完全图:每两个点都相连的图 其实就是一个有技巧的bfs,我们可以看到虽然点很多但边很少,就使用vector存下每个点在原图中可以到达其他的哪些点,再使用bfs寻找此时起点可以到的其他点(每个距离都是1,所以越早到距离越短),接着更新起点继续查找:我们需要使用数组记录此时起点不能到的一些点(就是vector中原图起点可以到的点),但每次通过起点判断其他所有的点会超时,因此我

HDU 5876:Sparse Graph(BFS)

http://acm.hdu.edu.cn/showproblem.php?pid=5876 Sparse Graph Problem Description In graph theory, the complement of a graph G is a graph H on the same vertices such that two distinct vertices of H are adjacent if and only if they are not adjacent in G

[HDOJ5876]Sparse Graph(补图最短路)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5876 题意:求一个图的补图中的单源最短路. 题解说:补图上的 BFS 是非常经典的问题.一般的做法是用链表(或者偷懒用 std::set)维护还没 BFS 过的点.当要扩展点 u 的时候,遍历一次还没访问过的点 v,如果 uv 没边,那么将 v 入队.否则将 v 留在未扩展点中.很明显,后者只会发生 m 次,前者只会发生 n 次,所以复杂度是 O(n + m). 总得说,求补图的最短路就是要存原图,

hdu_5876_Sparse Graph(补图BFS)

题目链接:hdu_5876_Sparse Graph 附上叉姐的题解: 1009 Sparse Graph [by ftiasch] 题意:n 个点的无向完全图中删除 m 条边,问点 s 到其他点的最短路长度. 题解: 补图上的 BFS 是非常经典的问题.一般的做法是用链表(或者偷懒用 std::set)维护还没 BFS 过的点.当要扩展点 u 的时候,遍历一次还没访问过的点 v,如果 uv 没边,那么将 v 入队.否则将 v 留在未扩展点中. 很明显,后者只会发生 m 次,前者只会发生 n 次

HDU 5876 补图 单源 最短路

---恢复内容开始--- Sparse Graph Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 2590    Accepted Submission(s): 902 Problem Description In graph theory, the complement of a graph G is a graph H on t