https://oj.neu.edu.cn/problem/1387

给一个点数N <= 100000, 边 <= 1000000的无向图,求补图的联通块数,以及每个块包含的点数

由于点数太大,补图会是稠密图,甚至建立补图都要O(n^2),只能挖掘一下联通块,bfs,补图的性质,从原图入手求补图的联通块:

在原图中不直接相邻的点,在补图中一定属于同一个联通块

每个点只属于一个联通块,所以找好一个联通块之后可以删去这个联通块的所有点,把图规模缩小

这样子:1.准备一个集合放所有未探索的点,初始化时将1~N放进去

2.从集合中取一点放入队列(新的联通块)

3.当队列不为空时,从队列中取一个点u并弹出,将原图中与u直接相连的点标记;遍历集合,将在集合中的(即未探索的)并且未被标记的点(这些点属于本联通块)入队并从集合中删去,将标记删去。重复执行直到队列为空

4.集合不为空转2,为空结束

考虑有删除操作和时间问题,集合的实现当然是选择链表,用数组实现的双向链表即可 

优化有两个:一是通过原图找补图的联通块;二是把搜过的点删除,这样每次找未标记的点时比起从1循环到N更优(常数优化(误))

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int maxn = 1e5+, maxm = 1e6+, inf = 0x3f3f3f3f;
struct lnk{
int val;
int pre, nxt;
}lk[maxn];
struct edge{
int v, nxt;
}e[maxm*];
int head[maxn], tot, block_cnt, n, m;
int adj[maxn], vis[maxn], num[maxn];
void addedge(int u, int v){
e[tot] = (edge){v, head[u]};
head[u] = tot++;
}
void dele(int x){
lk[lk[x].nxt].pre = lk[x].pre;
lk[lk[x].pre].nxt = lk[x].nxt;
}
void src(){
for(int i = ; i <= n; i++){
vis[i] = adj[i] = ;
}
queue<int>Q;
block_cnt = ;
while(lk[].nxt != -){
//puts("blk++");
Q.push(lk[].nxt);
//printf("take %d\n", lk[0].nxt);
vis[lk[lk[].nxt].val] = ;
dele(lk[].nxt);
block_cnt++;
num[block_cnt] = ;
while(!Q.empty()){
int x = Q.front();
x = lk[x].val;
//printf("%d\n", x);
Q.pop();
for(int i = head[x]; ~i; i = e[i].nxt){
int v = e[i].v;
adj[v] = ;
}
for(int i = lk[].nxt; ~i; i = lk[i].nxt){
int w = lk[i].val;
if(!vis[w] && !adj[w]){
Q.push(w);
vis[w] = ;
dele(i);
num[block_cnt]++;
}
}
for(int i = head[x]; ~i; i = e[i].nxt){
int v = e[i].v;
adj[v] = ;
}
}
}
}
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++)
head[i] = -;
tot = ;
while(m--){
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
for(int i = ; i <= n; i++){
lk[i].val = i;
lk[i].pre = i-;
lk[i].nxt = i+;
}
lk[n].nxt = -;
lk[].nxt = ;
src();
sort(num+, num+block_cnt+);
printf("%d\n", block_cnt);
for(int i = ; i <= block_cnt; i++){
printf("%d%c", num[i], i == block_cnt ? '\n' : ' ');
}
}
return ;
}
/*
3
5 7
1 2
1 3
1 4
1 5
2 3
2 4
2 5
6 9
1 4 1 5 1 6
2 4 2 5 2 6
3 4 3 5 3 6
3 3
1 2 2 3 3 1 */

链表加bfs求补图联通块的更多相关文章

  1. Codeforces Round #369 (Div. 2) D. Directed Roads dfs求某个联通块的在环上的点的数量

    D. Directed Roads   ZS the Coder and Chris the Baboon has explored Udayland for quite some time. The ...

  2. Feeding Time 【bfs求最大连通块】

    题目链接:https://ac.nowcoder.com/acm/contest/1870/J 题目大意:求最大的连通块是多大 主要是为了防止自己忘记bfs怎么写..... #include<s ...

  3. 分别利用并查集,DFS和BFS方法求联通块的数量

    联通块是指给定n个点,输入a,b(1<=a,b<=n),然后将a,b连接,凡是连接在一起的所有数就是一个联通块: 题意:第一行输入n,m,分别表示有n个数,有输入m对连接点,以下将要输入m ...

  4. 图-用DFS求连通块- UVa 1103和用BFS求最短路-UVa816。

    这道题目甚长, 代码也是甚长, 但是思路却不是太难.然而有好多代码实现的细节, 确是十分的巧妙. 对代码阅读能力, 代码理解能力, 代码实现能力, 代码实现技巧, DFS方法都大有裨益, 敬请有兴趣者 ...

  5. 【UVA10765】Doves and bombs (BCC求割点后联通块数量)

    题目: 题意: 给了一个联通无向图,现在问去掉某个点,会让图变成几个联通块? 输出的按分出的从多到小,若相等,输出标号从小到大.输出M个. 分析: BCC求割点后联通块数量,Tarjan算法. 联通块 ...

  6. 【BZOJ 1098】办公楼(补图连通块个数,Bfs)

    补图连通块个数这大概是一个套路吧,我之前没有见到过,想了好久都没有想出来QaQ 事实上这个做法本身就是一个朴素算法,但进行巧妙的实现,就可以分析出它的上界不会超过 $O(n + m)$. 接下来介绍一 ...

  7. 用dfs求联通块(UVa572)

    一.题目 输入一个m行n列的字符矩阵,统计字符“@”组成多少个八连块.如果两个字符所在的格子相邻(横.竖.或者对角线方向),就说它们属于同一个八连块. 二.解题思路 和前面的二叉树遍历类似,图也有DF ...

  8. 2014 Super Training #4 E Paint the Grid Reloaded --联通块缩点+BFS

    原题: ZOJ 3781 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3781 题意: 给一个n*m的X,O构成的格子,对 ...

  9. POJ-3107 Godfather 求每个节点连接的联通块数量

    dp[n][2],维护儿子的联通块数量和父亲的联通块数量. 第一遍dfs求儿子,第二遍dfs求爸爸. #include<iostream> #include<cstring> ...

随机推荐

  1. 29 内置方法 eval | exec 元类 单例

    eval与exec内置方法 将字符串作为执行目标,得到响应结果 eval常用作类型转换:该函数执行完有返回值 exec拥有执行更复杂的字符串:可以形成名称空间 eval内置函数的使用场景:   1.执 ...

  2. 2-3、配置Filebeat

    配置Filebeat 提示:Filebeat modules为常见的日志格式提供了最快的入门操作. 如果要使用Filebeat模块,请跳过本节,包括剩余的入门步骤,并直接转到快速入门:Quick st ...

  3. C++智能指针剖析(上)std::auto_ptr与boost::scoped_ptr

    1. 引入 C++语言中的动态内存分配没有自动回收机制,动态开辟的空间需要用户自己来维护,在出函数作用域或者程序正常退出前必须释放掉. 即程序员每次 new 出来的内存都要手动 delete,否则会造 ...

  4. JDBC 连接

    转载至:https://www.liyongzhen.com/ 在这一小节,我们将学习DriverManager对象和connection对象. DriverManager对象用于从驱动里获取一个co ...

  5. adjustsFontSizeToFitWidth 与 NSLineBreakByCharWrapping 无法共用

    newLabel.lineBreakMode = NSLineBreakByCharWrapping; newLabel.text = content; newLabel.adjustsFontSiz ...

  6. docker 安装使用 mssql2017

    1.拉取镜像 官方文档参考 : https://docs.microsoft.com/zh-cn/sql/linux/quickstart-install-connect-docker?view=sq ...

  7. TweenMax.js

    适用于移动端和现代互联网的超高性能专业级动画插件Tweenmax是GreenSock 动画平台的核心,配合其他插件 可动画CSS属性.滤镜效果. 颜色. 声音. 色彩. 帧. 饱和度. 对比度. 色调 ...

  8. Spring 开发常见问题

    linux 下http 接收中文参数乱码 解决: 在application.yml配置文件中添加 spring: http: encoding: charset: GB2312

  9. TFS2015创建项目

    1,在TFS服务器上的团队项目集合中创建集合   2,创建集合完毕后,在VS2017中选择管理连接,创建对应的管理连接.     3,团队资源管理器中新建团队项目.后续就是下一步,下一步完成.帐号权限 ...

  10. 不可不知的表达式树(3)定制IQueryProvider

    前面我们说到利用表达式树技术实现LINQ-to-SQL,实际上可以针对任何数据源,实现LINQ-to-Everything.这里还涉及到两个重要的接口即IQueryable和IQueryProvide ...