0
点赞
收藏
分享

微信扫一扫

codeforces Connected Components(寻找补图的连通块)


http://codeforces.com/contest/920/problem/E


E. Connected Components?



time limit per test



memory limit per test



input



output


n vertices and 

codeforces Connected Components(寻找补图的连通块)_图论

 edges. Instead of giving you the edges that exist in the graph, we give you m unordered pairs (x, y) such that there is no edge between x and y, and if some pair of vertices is not listed in the input, then there is an edge between these vertices.

X such that for every two vertices from this set there exists at least one path in the graph connecting these vertices, but adding any other vertex to X


Input

n and m (1 ≤ n ≤ 200000, 

codeforces Connected Components(寻找补图的连通块)_图论_02

).

m lines follow, each containing a pair of integers x and y (1 ≤ x, y ≤ nx ≠ y) denoting that there is no edge between x and y. Each pair is listed at most once; (x, y) and (y, x) are considered the same (so they are never listed in the same test). If some pair of vertices is not listed in the input, then there exists


Output


k

k


Example


input


5 51 23 4 3 2 4 2 2 5


output


21 4



【题意】

输入一个n点m边的无向图,求其补图的连通块。

补图:在完全图中,去掉原图中的边。

【分析】

在原图中不相接的两个点,在补图中肯定相连。因此,对一个点u而言,标记其所有的邻接边,那么没被标记的点,就是补图中u的邻接点。找到u的补图中的邻接点之后,再由找到的这些点用同样的方法找到邻接点,从而找出整个连通块。很明显BFS维护最合适。

【代码】

#include<bits/stdc++.h>
#define mset(a,i) memset(a,i,sizeof(a))
using namespace std;
const int N=202020;
struct node{
    int t,next;
}e[N<<2];
int head[N],cnt;
void add(int u,int v)
{
    e[cnt]=node{v,head[u]};
    head[u]=cnt++;
}
bool vis[N],vi[N];
int d[N];
int ans[N];
int main()
{
    int n,m,u,v;
    while(cin>>n>>m)
    {
        mset(head,-1);cnt=0;
        while(m--)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        for(int i=1;i<=n;i++)d[i]=i;
        int dtop=n,top=0;

        mset(vis,0); //标记已完成的点
        mset(vi,0);  //标记相邻点
        queue<int>q;
        for(int j=1;j<=n;j++)if(!vis[j])
        {
            ans[top++]=0; //新连通块,bfs找到此连通块所有点
            q.push(j);
            while(!q.empty())
            {
                int u=q.front();q.pop();
                vis[u]=1;
                ans[top-1]++;
                for(int i=head[u];~i;i=e[i].next) //当前图的邻接点
                    if(!vis[e[i].t])
                        vi[e[i].t]=1;
                for(int i=1;i<=dtop;)
                {
                    if(!vis[d[i]]&&!vi[d[i]]) //反图的相邻点
                    {
                        q.push(d[i]);
                        d[i]=d[dtop--]; //删除点d[i](优化)
                    }
                    else vi[d[i++]]=0;
                }
            }
        }
        sort(ans,ans+top);
        printf("%d\n",top);
        for(int i=0;i<top;i++)
            printf("%d%c",ans[i],i<top-1?' ':'\n');
    }
}


举报

相关推荐

0 条评论