zoukankan      html  css  js  c++  java
  • Codeforces Round #599 (Div. 2) D. 0-1 MST (补图连通块计数)

     

    Ujan has a lot of useless stuff in his drawers, a considerable part of which are his math notebooks: it is time to sort them out. This time he found an old dusty graph theory notebook with a description of a graph.

    It is an undirected weighted graph on nn vertices. It is a complete graph: each pair of vertices is connected by an edge. The weight of each edge is either 00 or 11; exactly mm edges have weight 11, and all others have weight 00.

    Since Ujan doesn't really want to organize his notes, he decided to find the weight of the minimum spanning tree of the graph. (The weight of a spanning tree is the sum of all its edges.) Can you find the answer for Ujan so he stops procrastinating?

    Input

    The first line of the input contains two integers nn and mm (1n1051≤n≤105, 0mmin(n(n1)2,105)0≤m≤min(n(n−1)2,105)), the number of vertices and the number of edges of weight 11 in the graph.

    The ii-th of the next mm lines contains two integers aiai and bibi (1ai,bin1≤ai,bi≤n, aibiai≠bi), the endpoints of the ii-th edge of weight 11.

    It is guaranteed that no edge appears twice in the input.

    Output

    Output a single integer, the weight of the minimum spanning tree of the graph.

    Examples
    input
    Copy
    6 11
    1 3
    1 4
    1 5
    1 6
    2 3
    2 4
    2 5
    2 6
    3 4
    3 5
    3 6
    
    output
    Copy
    2
    
    input
    Copy
    3 0
    
    output
    Copy
    0
    
    Note

    The graph from the first sample is shown below. Dashed edges have weight 00, other edges have weight 11. One of the minimum spanning trees is highlighted in orange and has total weight 22.

    In the second sample, all edges have weight 00 so any spanning tree has total weight 00.

     

     

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <cstdlib>
    #include <map>
    #include <vector>
    #include <set>
    #include <queue>
    #include <stack>
    #include <cmath>
    using namespace std;
    #define mem(s,t) memset(s,t,sizeof(s))
    #define pq priority_queue
    #define pb push_back
    #define fi first
    #define se second
    #define ac return 0;
    #define ll long long
    #define cin2(a,n,m)     for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
    #define rep_(n,m)  for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    #define rep(n) for(int i=1;i<=n;i++)
    #define test(xxx) cout<<"  Test  " <<" "<<xxx<<endl;
    #define TLE std::ios::sync_with_stdio(false);   cin.tie(NULL);   cout.tie(NULL);   cout.precision(10);
    #define lc now<<1
    #define rc now<<1|1
    #define ls now<<1,l,mid
    #define rs now<<1|1,mid+1,r
    #define half no[now].l+((no[now].r-no[now].l)>>1)
    #define ll long long
    #define inf 0x3f3f3f3f
    #define mod 1000000007
    const int mxn = 1e5+10;
    int n,m,k,ans,col,t,flag,vis[mxn];
    ll dp[mxn],pro[mxn];
    string str,ch ;
    map<char,int>mp;
    set<int>st,G[mxn];
    pair <int,int> pa[mxn];
    bool cmp(pair<int,int>x,pair<int,int>y)
    {
        return x.first>y.first;
    }
    void BFS(int x)
    {
        queue<int>q;
        q.push(x);
        st.erase(x);
        while(q.size())
        {
            int now = q.front();
            q.pop();
            if(vis[now])
                continue;
            vis[now] = 1 ;
            for(set<int>::iterator it=st.begin(); it!=st.end();)
            {
                int cnt = *it;
                it++;//set和vector这些容器不能边修改边遍历,需要在修改之前将迭代器往后加一
                if(G[now].find(cnt)==G[now].end())
                {
                    q.push(cnt);
                    st.erase(cnt);
                }
            }
        }
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            st.insert(i);
        for(int i=1; i<=m; i++)
        {
            cin>>col>>ans;
            G[col].insert(ans);
            G[ans].insert(col);
        }
        ans = 0;
        for(int i=1; i<=n; i++)
        {
            if(!vis[i])
            {
                BFS(i);
                ans++;
            }
        }
        cout<<ans-1<<endl;
        return 0;
    }

     

    //聚聚:并查集,用set存已经被放入并查集的点,对于没有放入的点,计算该点和联通块相连的点的个数,如果相连的点的个数小于联通块大小,则直接连进去即可。时间复杂度O(n+m∗log)
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e6+100;
    int par[N],siz[N];
    int cnt[N];
    struct edge{
        int u,v,w;
    }e[N];
    vector<int> G[N];
    int find(int x){
        return x==par[x]?x:par[x]=find(par[x]);
    }
    void unite(int x,int y){
        x=find(x);
        y=find(y);
        if(x==y) return ;
        par[x]=y;
        siz[y]+=siz[x];
    }
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        int n,m,u,v;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            par[i]=i;
            siz[i]=1;
        }
        for(int i=1;i<=m;i++){
            cin>>u>>v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        int ans=n-1;
        set<int> st;
        st.insert(1);
        for(int i=2;i<=n;i++){
            for(int v:G[i]){
                cnt[find(v)]++;//和各联通块相连的点的个数
            }
            for(auto it=st.begin();it!=st.end();){
                int an=find(*it);
                if(cnt[an]<siz[an]){
                    unite(*it,i);
                    st.erase(it++);
                    ans--;
                }else it++;
            }
            for(int v:G[i]) cnt[find(v)]=0;
            st.insert(i);
        }
        cout<<ans<<endl;
        return 0;
    }
    所遇皆星河
  • 相关阅读:
    Win7操作系统防火墙无法关闭的问题 无法找到防火墙关闭的地方的解决的方法
    【微信】微信获取TOKEN,以及储存TOKEN方法,Spring quartz让Token永只是期
    OC内存管理总结,清晰明了!
    下次自己主动登录(记住password)功能
    linux删除svn版本号库
    Python中可避免读写乱码的一个强慷慨法
    Tomcat源代码阅读#1:classloader初始化
    iOS关于图片点到像素转换之杂谈
    hdu 3804树链剖分+离线操作
    cdn缓存
  • 原文地址:https://www.cnblogs.com/Shallow-dream/p/11853785.html
Copyright © 2011-2022 走看看