链表加bfs求补图联通块
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求补图联通块的更多相关文章
- 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 ...
- Feeding Time 【bfs求最大连通块】
题目链接:https://ac.nowcoder.com/acm/contest/1870/J 题目大意:求最大的连通块是多大 主要是为了防止自己忘记bfs怎么写..... #include<s ...
- 分别利用并查集,DFS和BFS方法求联通块的数量
联通块是指给定n个点,输入a,b(1<=a,b<=n),然后将a,b连接,凡是连接在一起的所有数就是一个联通块: 题意:第一行输入n,m,分别表示有n个数,有输入m对连接点,以下将要输入m ...
- 图-用DFS求连通块- UVa 1103和用BFS求最短路-UVa816。
这道题目甚长, 代码也是甚长, 但是思路却不是太难.然而有好多代码实现的细节, 确是十分的巧妙. 对代码阅读能力, 代码理解能力, 代码实现能力, 代码实现技巧, DFS方法都大有裨益, 敬请有兴趣者 ...
- 【UVA10765】Doves and bombs (BCC求割点后联通块数量)
题目: 题意: 给了一个联通无向图,现在问去掉某个点,会让图变成几个联通块? 输出的按分出的从多到小,若相等,输出标号从小到大.输出M个. 分析: BCC求割点后联通块数量,Tarjan算法. 联通块 ...
- 【BZOJ 1098】办公楼(补图连通块个数,Bfs)
补图连通块个数这大概是一个套路吧,我之前没有见到过,想了好久都没有想出来QaQ 事实上这个做法本身就是一个朴素算法,但进行巧妙的实现,就可以分析出它的上界不会超过 $O(n + m)$. 接下来介绍一 ...
- 用dfs求联通块(UVa572)
一.题目 输入一个m行n列的字符矩阵,统计字符“@”组成多少个八连块.如果两个字符所在的格子相邻(横.竖.或者对角线方向),就说它们属于同一个八连块. 二.解题思路 和前面的二叉树遍历类似,图也有DF ...
- 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构成的格子,对 ...
- POJ-3107 Godfather 求每个节点连接的联通块数量
dp[n][2],维护儿子的联通块数量和父亲的联通块数量. 第一遍dfs求儿子,第二遍dfs求爸爸. #include<iostream> #include<cstring> ...
随机推荐
- springboo+nginx测试反向代理02
本节对nginx配置方面会略微研究~~ 1:切换到 /opt/nginx-1.8.1/conf 目录,将nginx.conf文件拷贝到 /myprojects/nginx 目录下 2:切换到/opt/ ...
- C# 最全的文件工具类FileHelper
using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Lin ...
- 我的第一个SpringProject——HelloWorld
我的第一个Spring项目HelloWorld还是花了不少时间,在工具配置上耽误了 我使用的是Eclipse,开始Maven+intellij+Spring搞不太懂 首先要配置Spring: 打开ec ...
- 记录一个EF连接查询的异常:the entity or complex type 'x' cannot be constructed in a linq to entities query
问题解决连接:https://stackoverflow.com/questions/5325797/the-entity-cannot-be-constructed-in-a-linq-to-ent ...
- 小程序:navigateBack()修改数据
1.获取当前页面js里面的pages里的所有信息var pages = getCurrentPages(); 2. -2上一个页面 -3是上上个页面 var prevPage = pages[p ...
- centOS6.5 mysql-community-server安装失败
卸载mysql,重新装 yum install mysql-server 图中没有放卸载的图 [root@cgrctenOS6 ~]# yum install mysql-community-serv ...
- Flask路由&视图
1 路由 1.1app.url_map 查看所有路由 from flask import Flask app = Flask(__name__) @app.route('/') def hello_ ...
- VMware14虚拟机上使用Ubuntu16.04遇到的各种问题(不定期更新)
1.ubuntu系统界面无法全屏铺满的问题 网上大部分解决方案都是使用vmware tools,我没尝试过,不过这里推荐一个更加简单的方法,只需要输入两行命令 第一步:sudo apt-get ins ...
- CentOS7各个版本镜像下载地址
# CentOS7.6 下载地址 # CentOS-7-x86_64-DVD-1810.iso CentOS 7.6 DVD 版 4G http://mirrors.163.com/centos/7. ...
- JpaManytoMany
package com.allqj.calculator.entity; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; i ...