【bzoj1098】办公楼

题意

FGD开办了一家电话公司。他雇用了N个职员,给了每个职员一部手机。每个职员的手机里都存储有一些同事的电话号码。由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一些新的办公楼。FGD希望职员被安置在尽量多的办公楼当中,这样对于每个职员来说都会有一个相对更好的工作环境。但是,为了联系方便起见,如果两个职员被安置在两个不同的办公楼之内,他们必须拥有彼此的电话号码。

\(2<=N<=100000,1<=M<=2000000\)

分析

要求块内任意,块外充满连边的最小划分数。

那就等价于补图上块内任意,块外无连边的最小划分数。

那么就等价于求补图的联通块个数。

对\(n=100000\)的稠密图来讲,

直接求联通块会炸。

所以要利用到\(M\leq 2000000\)的特性。

我最初的想法是:我们可以枚举任意一对的\((i,j)\),若它们在原图中不存在连边,那么用并查集把它们合并。

由于这是一幅稠密图,所以\((i,j)\)有很大的概率存在连边,所以我们对于每个点\(i\),不需要枚举所有的\(j\),只需要随机枚举\(T\)个,然后尝试连边即可。

然而WA了......

接下来说的是正解。

求连通块的方法常有搜索或者并查集。

并查集看似不行,我们考虑搜索的过程,并根据\(M\leq 2000000\)的特性优化。

BFS:对于一个点\(i\),找与它连通的所有点\(j\),再找与\(j\)连通的所有点\(k\)......

把所有找到的点删去,ans++。

普通的实现上,最大的瓶颈在于已经删除的点我们还反复枚举了......

那么我们就不反复枚举好了,直接使用双向链表来删点,复杂度就优化到了\(O(n)\),因为最多有\(2M\)次失败。

还看到一种更精彩的代替双向链表的做法。

就是直接使用并查集代替双向链表。

代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;

#define rep(i,a,b) for (int i=(a);i<=(b);i++)

const int N=131072;

int n,m;
vector<int> g[N];

int vis[N],f[N];
int cnt[N],len;
int hsn[N],q[N],qh,qt;

int rd(void) {
    int x=0,f=1; char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

int Find(int x) {
    if (f[x]==x) return x;
    return f[x]=Find(f[x]);
}

void Erase(int st) {
    qh=qt=0; q[++qt]=st; vis[st]=1;
    cnt[len]++;
    f[st]=Find(st+1);
    while (qh!=qt) {
        int x=q[++qh];
        rep(i,1,g[x].size()) {
            int nx=g[x][i-1];
            hsn[nx]=1;
        }
        int nx=Find(1);
        while (nx!=n+1) {
            if (!hsn[nx]) {
                q[++qt]=nx; vis[nx]=1; cnt[len]++;
                f[nx]=Find(nx+1);
            }
            nx=Find(nx+1);
        }
        rep(i,1,g[x].size()) {
            int nx=g[x][i-1];
            hsn[nx]=0;
        }
    }
}

int main(void) {
    #ifndef ONLINE_JUDGE
    freopen("sd.in","r",stdin);
    freopen("sd.out","w",stdout);
    #endif

    n=rd(),m=rd();
    rep(i,1,m) {
        int x=rd(),y=rd();
        g[x].push_back(y),g[y].push_back(x);
    }

    rep(i,1,n+1) f[i]=i;
    rep(i,1,n) if (!vis[i]) {
        len++;
        Erase(i);
    }

    sort(cnt+1,cnt+len+1);
    printf("%d\n",len);
    rep(i,1,len)
        printf("%d ",cnt[i]);
    printf("\n");

    return 0;
}

小结

(1)并查集可以代替双向链表,且实现更容易。

(2)外界充满边=补图外界无边,注意充满边的转化方法,最大团也是充满边的一种体现形式。

(3)连通块个数的统计,通常使用并查集或者搜索实现。

【bzoj1098】办公楼的更多相关文章

  1. bzoj1098 办公楼

    Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决 ...

  2. 5098: [BZOJ1098][POI2007]办公楼biu

    5098: [BZOJ1098][POI2007]办公楼biu 没有数据结构就很棒 一个看上去非常玄学的代码 const int N=1e5+10,M=2e6+10; int n,m; int fa[ ...

  3. BZOJ1098: [POI2007]办公楼biu

    从问题可以看出是求补图的连通块及点数 但补图太大.所以考虑缩小规模. 当一个点归属于一个连通块后,它以后就不需要了.所以可以用链表,删去这个点,也就减小了规模. 一个点开始bfs,每个点只会进队一次, ...

  4. 【链表】Bzoj1098[POI2007]办公楼biu

    Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决 ...

  5. BZOJ1098 POI2007 办公楼biu 【链表+bfs】

    Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决 ...

  6. 【BZOJ1098】[POI2007]办公楼biu

    题目一开始看以为和强联通分量有关,后来发现是无向边,其实就是求原图的补图的联通块个数和大小.学习了黄学长的代码,利用链表来优化,其实就是枚举每一个人,然后把和他不相连的人都删去放进同一个联通块里,利用 ...

  7. 【BZOJ1098】办公楼biu(补图,bfs,链表)

    题意:有n个点m条边,要求将点尽可能多的分成若干个部分,使得若两个点不在同一个部分则他们之间必定有边 n<=1e5,m<=2e6 思路:From https://blog.csdn.net ...

  8. 【BZOJ】1098: [POI2007]办公楼biu(补图+bfs+链表)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1098 显然答案是补图连通块..... 想到用并查集...可是连补图的边都已经...n^2了...怎么 ...

  9. 办公楼[POI2007]

    题目描述 FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一 ...

随机推荐

  1. FlipView 索引为0 WP8.1

    如果使用FlipView时,出现别的页面切换到含有FlipView的页面时(缓存此页面/MainPage),点击或者滑动FlipView,Flipview自动索引到0 的问题解决办法 1.对Flipv ...

  2. linux下安装编译php的curl扩展

    curl扩展的位置(需要编译的版本)/root/install/php-5.5.24/ext/curl 1.进入对应的扩展目录 # cd /root/install/php-5.5.24/ext/cu ...

  3. 关于Thread.IsBackground属性的理解(转载)

    C#中,Thread类有一个IsBackground 的属性.MSDN上对它的解释是:获取或设置一个值,该值指示某个线程是否为后台线程.个人感觉这样的解释等于没有解释. .Net中的线程,可以分为后台 ...

  4. MyBatis(2):config.xml文件

    前言 前一篇文章,讲了MyBatis入门,讲到了MyBatis有两个基本的配置文件,一个用来配置环境信息,一个用来写SQL语句.前者我把它命名为config.xml,config.xml的内容是: 1 ...

  5. poj 1888 Crossword Answers 模拟题

    Crossword Answers Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 869   Accepted: 405 D ...

  6. 夺命雷公狗-----React---13--事件监听

    在react中事件监听直接作为组建的属性来添加即可,就像DOM中的html操作 <!DOCTYPE> <html> <head> <meta charset= ...

  7. python学习笔记系列----(二)控制流

    实际开始看这一章节的时候,觉得都不想看了,因为每种语言都会有控制流,感觉好像我不看就会了似的.快速预览的时候,发现了原来还包含了对函数定义的一些描述,重点讲了3种函数形参的定义方法,章节的最后讲述了P ...

  8. 助手系列之python的FTP服务器

    电脑的OS是Win7,Python版本是2.7.9,安装了pip 因为python没有内置可用的FTP SERVER,所以先选一个第三方的组件安装上,这里我选的是pyftpdlib pip insta ...

  9. "未能找到类型或命名空间名称",引用dll的时候出错

    当前项目是.net2.0框架,引用的dll是 .net 4.5框架,引用后编译时报错“未能找到类型或命名空间名称”. 当前项目 右键-->应用程序-->目标框架 改为 .net frame ...

  10. sql按时间段汇总

    select dateadd(mi,(datediff(mi,convert(varchar(10),dateadd(ss,-1,CreateOn),120),dateadd(ss,-1,Create ...