题意:给你原图的补图,求原图的连通块个数,与每个连通块大小。
#include<stdio.h>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
vector<int>vt[200005];
int ok[200005],mark[200005];
int sta[200005],tot;
int last[200005],nxt[200005];
queue<int>que;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int _read(){
char ch=nc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
int main()
{
int n,m;
//scanf("%d%d",&n,&m);
n=_read();
m=_read();
for(int i=0;i<m;i++)
{
int u,v;
//scanf("%d%d",&u,&v);
u=_read();
v=_read();
vt[u].push_back(v);
vt[v].push_back(u);
}
for(int i=1;i<=n;i++)
last[i]=i-1,nxt[i]=i+1;
nxt[0]=1;last[n+1]=n;
for(int i=1;i<=n;i++)
{
if(ok[i])continue;
que.push(i);
tot++;
int la=last[i],nx=nxt[i];
nxt[la]=nx;
last[nx]=la;
while(!que.empty())
{
int k=que.front();
que.pop();
sta[tot-1]++;
ok[k]=1;
for(int j=0;j<vt[k].size();j++)
mark[vt[k][j]]=1;
for(int j=nxt[0];j<=n;j=nxt[j])
{
if(mark[j])continue;
que.push(j);
int la=last[j],nx=nxt[j];
nxt[la]=nx;
last[nx]=la;
}
for(int j=0;j<vt[k].size();j++)
mark[vt[k][j]]=0;
}
}
sort(sta,sta+tot);
printf("%d\n",tot);
for(int i=0;i<tot;i++)
printf("%d ",sta[i]);
} 题解:将点划分为,未归纳如连通块与已经被归纳入某个连通块两种情况,for所有未归纳的点,对于当前点i遍历所有其他未归纳的点,若原图有边则将该点加入。通过链表维护未归纳的点,时间复杂度为O(n+m)。
AC代码:

本文介绍了一种算法,用于解决给定原图的补图时如何计算原图的连通块个数及各连通块大小的问题。通过遍历未归纳的点并使用链表维护状态,实现O(n+m)的时间复杂度。
457

被折叠的 条评论
为什么被折叠?



