当前位置 博文首页 > 代码笔记本:1242B - 0-1 MST(求补图的连通块)

    代码笔记本:1242B - 0-1 MST(求补图的连通块)

    作者:[db:作者] 时间:2021-09-21 20:55

    https://codeforces.com/problemset/problem/1242/B


    思路:

    trick。边太多考虑点。先放下所有点的集合。然后把在原图中无法一次遍历到的点就是在补图上有边相连的。然后这些点可以相成一个连通块。就是补图的连通块。补图连通块的两两之间需要代价为1的原图上的边。

    极限情况下全都是1边,可以卡到n^2logn。但是这样点数最多只有10^3,所以比较稳

    #include<iostream>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<cmath>
    #include<map>
    #include<set>
    #include<cstdio>
    #include<algorithm>
    #define debug(a) cout<<#a<<"="<<a<<endl;
    using namespace std;
    const int maxn=1e5+1000;
    typedef int LL;
    inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;}
    multiset<LL>s;
    multiset<LL>g[maxn];
    LL vis[maxn];
    void bfs(LL x){
        s.erase(x);
        vis[x]=true;
        queue<LL>que;
        que.push(x);
        while(!que.empty()){
            LL u=que.front();que.pop();
            for(auto it=s.begin();it!=s.end();){
                LL v=*it++;
                if(!g[u].count(v)){
                    s.erase(v);
                    que.push(v);
                    vis[v]=true;
                }
            }
        }
    }
    int main(void){
       LL n,m;n=read();m=read();
       for(LL i=1;i<=n;i++) s.insert(i);
       for(LL i=1;i<=m;i++){
          LL u,v;u=read();v=read();
          g[u].insert(v);g[v].insert(u);
       }
       LL ans=0;
       for(LL i=1;i<=n;i++){
          if(!vis[i]){
             ans++;
             bfs(i);
          }
       }
       printf("%d\n",ans-1);
       return 0;
    }
    

    ?

    cs