BZOJ1098 办公楼biu (BFS+链表优化)

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1098分析:见注释。
 1 // 补图连通块 bfs + 链表优化
 2 #include <cstdio>
 3 #include <queue>
 4 #include <vector>
 5 #include <algorithm>
 6 using namespace std;
 7
 8 struct Edge {
 9     int to, nxt;
10 };
11
12 struct Node {
13     int pre, nxt;
14 };
15
16 const int maxm = 2000000 + 5;
17 const int maxn = 100000 + 5;
18
19 int n, m, cnt;
20 int head[maxn], vis[maxn], vi[maxn];
21 Edge e[maxm << 1];
22 Node l[maxn];
23 vector<int> ans;
24
25 void add_edge(int u, int v) {
26     e[++cnt].to = v; e[cnt].nxt = head[u]; head[u] = cnt;
27     e[++cnt].to = u; e[cnt].nxt = head[v]; head[v] = cnt;
28 }
29
30 void del_node(int p) {
31     l[l[p].pre].nxt = l[p].nxt;
32     l[l[p].nxt].pre = l[p].pre;
33 }
34
35 void bfs() {
36     queue<int> q; // 维护当前补图连通块中要扩展的节点
37     while (l[0].nxt != 0) { // 当前链表不为空,说明还有节点未属于任何连通块
38         int p = l[0].nxt; // 枚举链表中存在的一个节点,成为一个新的连通块中的第一个节点
39         del_node(p); // 从链表中删除此节点
40         q.push(p); // 节点入队
41         int sum = 1; // 当前连通块数量为1
42         while (!q.empty()) { // 不断对属于当前连通块中的节点求其补图连通节点从链表中删除并加入队列
43             p = q.front(); q.pop(); // 弹出连通块中的一个节点
44             for (int i = head[p]; i; i = e[i].nxt) // 枚举此节点的边并标记
45                 vis[e[i].to] = 1;
46             for (int i = l[0].nxt; i; i = l[i].nxt) // 查找当前还未属于任何连通块的节点,如果未被标记则属于p的补图连通节点,此连通块的节点数目自增,并将联通节点加入队列然后从链表中删除
47                 if (!vis[i]) { sum++; q.push(i); del_node(i); }
48             for (int i = head[p]; i; i = e[i].nxt) vis[e[i].to] = 0; // 恢复标记,被标记的节点可能为当前块中(队列中的)需要扩展的节点的补图连通节点
49         }
50         ans.push_back(sum); // 将完整的连通块中的节点数目保存在数组中
51     }
52 }
53
54 int main() {
55     scanf("%d%d", &n, &m);
56     for (int i = 1, u, v; i <= m; i++) { // 建图
57         scanf("%d%d", &u, &v);
58         add_edge(u, v);
59     }
60     for (int i = 1; i <= n; i++) { // 将节点1 ~ N初始化为一个链表(维护未在任何连通块中的节点),l[0].nxt指向当前链表中的表头节点, 链表为空的条件是l[0].nxt = 0
61         l[i].pre = i - 1;
62         l[i].nxt = i + 1;
63     } l[0].nxt = 1; l[n].nxt = 0;
64     bfs(); // bfs求补图连通块
65     printf("%d\n", ans.size()); // 输出连通块数目
66     sort(ans.begin(), ans.end()); // 将各个连通块数目按升序排序
67     for (int i = 0; i < ans.size(); i++) // 升序输出各连通块数目
68         printf("%d ", ans[i]);
69     return 0;
70 }
时间: 2024-10-10 04:40:39

BZOJ1098 办公楼biu (BFS+链表优化)的相关文章

[BZOJ 1098] [POI2007] 办公楼biu 【链表优化BFS】

题目链接:BZOJ - 1098 题目分析 只有两个点之间有边的时候它们才能在不同的楼内,那么就是说如果两个点之间没有边它们就一定在同一座楼内. 那么要求的就是求原图的补图的连通块. 然而原图的补图的边数是 n^2 级别的,非常庞大,我们不能直接把补图求出来. 可以使用一种用链表优化BFS的做法,开始时将所有的点加到一个链表里. 每次找一个连通块的时候BFS,在链表中取出一个点,在链表中删除,加入队列,然后每次取出队首元素x,枚举x的每一条边,将边的终点y从链表中删去,加到一个临时的链表中存储.

bzoj 1098 [POI2007]办公楼biu bfs+补图+双向链表

[POI2007]办公楼biu Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1543  Solved: 743[Submit][Status][Discuss] Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一些新的办公楼.FGD希望职员被安置在尽量多的办公楼当中,这样对于每个职员

BZOJ1098: [POI2007]办公楼biu

1098: [POI2007]办公楼biu Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 777  Solved: 326[Submit][Status] Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一些新的办公楼. FGD希望职员被安置在尽量多的办公楼当中,这样对于每个职员来说都

HDU4941Magical Forest (二分+链表优化)

Magical Forest Time Limit: 24000/12000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 510 Accepted Submission(s): 239 Problem Description There is a forest can be seen as N * M grid. In this forest, there is some ma

BZOJ 1098 [POI2007]办公楼biu 链表

description Bytel is a mobile telephony potentate. Each employee has been issued a company phone, the memory ofwhich holds the numbers of some of his co-workers (all of them have his number in their phones as well). Due to dynamic growth of their ope

【BZOJ1098】[POI2007]办公楼biu

题目一开始看以为和强联通分量有关,后来发现是无向边,其实就是求原图的补图的联通块个数和大小.学习了黄学长的代码,利用链表来优化,其实就是枚举每一个人,然后把和他不相连的人都删去放进同一个联通块里,利用bfs来实现.——by VANE #include<bits/stdc++.h> using namespace std; const int N=100005; const int M=4000005; struct edge{int to,next;}e[M]; int a[N],q[N];

bzoj 1098 [POI2007] 办公楼 biu

# 解题思路 画画图可以发现,只要是两个点之间没有相互连边,那么就必须将这两个人安排到同一个办公楼内,如图所示: 那,我们可以建立补图,就是先建一张完全图,然后把题目中给出的边都删掉,这就是一张补图,显然补图中相互连边的点就放在同一栋办公楼内. 我们可以用并查集来完成,但是数据范围显然不允许用这样的方法,建图的复杂度是 $N^2$ 的.所以考虑另一种方法: 将原图建立好,在原图中,从一个点开始,把这个点所能够直接到达的点标记出来,这些点是不可以放在一起的.然后将这些点删除. 之后对每一个点都进行

poj 1324 Holedox Moving A*算法对bfs的优化

题意: 迷宫里有一条贪食蛇,求它的蛇头到迷宫左上角最少要多少步. 分析: 关键是将蛇的状态压缩编码,然后bfs,超时就改A*,这题有类似最短路径的性质,A*发现节点重复后不需要更新直接舍弃即可. 代码: //poj 1324 //sep9 #include <iostream> #include <algorithm> #include <queue> using namespace std; struct state { int x[10],y[10]; }; str

hdu1072 bfs时间优化剪枝

Nightmare Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9424    Accepted Submission(s): 4551 Problem Description Ignatius had a nightmare last night. He found himself in a labyrinth with a tim