求补图的联通块数(bzoj 1098+codefoces920E)

2024-04-05 21:18

本文主要是介绍求补图的联通块数(bzoj 1098+codefoces920E),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

思路:链表加BFS的强优化,具体是这样的:我们先把所有的节点挂链,然后再把链表上的一个节点入队,遍历其在原图上相邻的点并做上标记,那么这时没有打上标记的点在补图上和当前节点一定有边相连因而一定在同一个联通块中,所以再把这些没有打上标记的点入队,并且在链表中除去,继续这个过程,直到队列为空时这个联通块就找出来了,再取链表上还存在的点入队寻找一个新的联通块,直到删掉所有点为止,复杂度降为了O(n + m)。

代码:

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2*1e5+5;
int n,m,head[2*maxn],cnt,vis1[maxn],vis2[maxn],ans[maxn],ct;
struct node
{int v,nxt;
} e[2*maxn];
struct link
{int pre,nxt;
} L[maxn];void init()
{memset(head,-1,sizeof(head));for(int i=1; i<=n; i++){L[i-1].nxt=i;L[i].pre=i-1;}L[n].nxt=0;
}void add(int u,int v)
{e[cnt].v=v,e[cnt].nxt=head[u],head[u]=cnt++;
}void del(int x)
{L[L[x].pre].nxt=L[x].nxt;L[L[x].nxt].pre=L[x].pre;
}void bfs()
{queue<int> q;while(L[0].nxt){int now=L[0].nxt,tmp=1;vis2[now]=1;q.push(now);del(now);while(!q.empty()){int tp=q.front();q.pop();for(int i=head[tp]; ~i/*等价于i!=-1*/; i=e[i].nxt) vis1[e[i].v]=1;for(int i=L[0].nxt; i; i=L[i].nxt){if(!vis1[i] && !vis2[i]){vis2[i]=1;q.push(i);del(i);tmp++;}}for(int i=head[tp]; ~i; i=e[i].nxt) vis1[e[i].v]=0;///取消标记 防止干扰下一次的判断}ans[ct++]=tmp;tmp=1;}
}int main()
{ios::sync_with_stdio(false);cin>>n>>m;init();for(int i=0; i<m; i++){int a,b;cin>>a>>b;add(a,b),add(b,a);}bfs();cout<<ct<<endl;sort(ans,ans+ct);for(int i=0; i<ct; i++)cout<<ans[i]<<" ";cout<<endl;
}

 

 

 

 

 

 

 

这篇关于求补图的联通块数(bzoj 1098+codefoces920E)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/878172

相关文章

【造轮子】纯C++实现的联通组件标记算法

学习《OpenCV应用开发:入门、进阶与工程化实践》一书 做真正的OpenCV开发者,从入门到入职,一步到位! 连接组件标记算法 连接组件标记算法(connected component labeling algorithm-CCL)是图像分析中最常用的算法之一,算法的实质是扫描一幅图像的每个像素,对于像素值相同的分为相同的组(group),最终得到图像中所有的像素连通组件。扫描的方式可以是从

【BZOJ】1324 Exca王者之剑 最大权独立集

传送门:【BZOJ】1324  Exca王者之剑 题目分析:赤裸裸的最大权独立集。。。最小割解决 代码如下: #include <cstdio>#include <vector>#include <cstring>#include <algorithm>using namespace std ;#define REP( i , a , b ) for ( int

【BZOJ】1026: [SCOI2009]windy数 数位DP

传送门:【BZOJ】1026: [SCOI2009]windy数 题目分析:数位DP水题。 代码如下: #include <stdio.h>#include <cstring>#include <algorithm>#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )#define For( i ,

【BZOJ】2152: 聪聪可可 点分治

传送门:【BZOJ】2152: 聪聪可可 题目分析:记录权值和%3的路径的个数。。。然后去重。。没了。。 代码如下: #include <vector>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std ;typedef lo

BZOJ 2440 2301 莫比乌斯应用

http://www.lydsy.com/JudgeOnline/problem.php?id=2440 Description 小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些 数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而 这丝毫不影响他对其他数的热爱。  这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一 个小X讨厌

HIHO #1190 : 连通性·四(点的双联通分量)

题目链接 点的双联通分量,不注意写出了一个bug,找了2个多小时= =,我的边存的是0开始的,然后ans数组一开始也是0,然后就是if的地方。。。。。 还是tarjan的算法,结合提示,这里需要存边,然后栈里面保存的是边,而不是点,这里我用边在边集es中的编号,作为边的标志 #include<bits/stdc++.h>using namespace std;#define cl(a,b

BZOJ 3732: Network(最小生成树+倍增)

题目链接 题意:给出一个图,每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少 很明显最终查询的边一定是在最小生成树里面的,先跑出最小生成树,然后,可以树链剖分,也可以使用倍增来计算 #include<bits/stdc++.h>using namespace std;#define cl(a,b) memset(a,b,sizeof(a))#define

--uva247(calling circles)强联通与floyd-warshell

图论题:一开始我是用tarjan算法做的,wrong answer 了很多次,然后又用了floyd-warshell算法,也wa了 最后找了题解,原来最后的dataset后面不是组数,是样例的编号,题根本就没说,让人怎么理解。。。 tarjan #include<stdio.h>#include<iostream>#include<string.h>#include<string>#

杭电 acm 1098

多校综合排名前25名的学校请发送邮件到HDUACM@QQ.COM,告知转账信息(支付宝或者卡号) Ignatius's puzzle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6372    Accepted S

BZOJ 2038 小Z的袜子(hose) (莫队离线)

题目地址:BZOJ 2038 裸的莫队算法。 代码如下: #include <iostream>#include <string.h>#include <math.h>#include <queue>#include <algorithm>#include <stdlib.h>#include <map>#include <set>#include <stdio.h>#in