zoukankan      html  css  js  c++  java
  • BZOJ 1098 [POI2007]办公楼biu(反向图bfs+并查集优化)

    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=1098

    【题目大意】

      现在有一张图,要求将这张图的点划分为尽量多的分组,对于不同分组的两个点
      要求必须存在连边。

    【题解】

      不同分组之间的两点必须连边等价于没有连边的点一定在同一分组内,
      所以题目转化为求反图的连通块和其大小,搜索的理论复杂度O(n^2),显然不行,
      bfs的时候对于已经归入其余连通块的点用并查集进行段无效信息处理,减少搜索树的分支,
      显然经过这样的处理搜索分支的数量下降得非常快,就能顺利解决此题了。

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <queue>
    using namespace std;
    const int N=100010;
    int f[N],n,m,vis[N],ans,cnt[N];
    vector<int> v[N];
    int sf(int x){return f[x]==x?x:f[x]=sf(f[x]);}
    void bfs(int st){
        queue<int> q;
        q.push(st);
        cnt[++ans]=1;
        while(q.size()){
            int x=q.front();q.pop();f[x]=sf(x+1);
            for(int i=0;i<v[x].size();i++)vis[v[x][i]]=x;
            for(int i=sf(1);i<=n;i=sf(i+1))if(vis[i]!=x){
                cnt[ans]++;
                f[i]=sf(i+1);
                q.push(i);
            }
        }
    }
    int main(){
        while(~scanf("%d%d",&n,&m)){
            ans=0;
            while(m--){
                int x,y;
                scanf("%d%d",&x,&y);
                v[x].push_back(y);
                v[y].push_back(x);
            }
            for(int i=1;i<=n+1;i++)f[i]=i;
            for(int i=1;i<=n;i=sf(i+1))bfs(i);
            printf("%d
    ",ans);
            sort(cnt+1,cnt+ans+1);
            for(int i=1;i<=ans;i++)printf("%d ",cnt[i]);
            puts("");
        }return 0;
    }
  • 相关阅读:
    第十章 嵌入式Linux的调试技术
    第九章 硬件抽象层:HAL
    第八章 让开发板发出声音:蜂鸣器驱动
    第八章GPS与Google Map定位系统
    第六章 接口驱动程序开发
    第七章 Android嵌入式组态软件
    第五章 S5PV210硬件结构
    第四章
    第三章
    第二章
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj1098.html
Copyright © 2011-2022 走看看