本文主要是介绍求补图的联通块数(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)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!