BZOJ 1098 [POI2007]办公楼biu 链表

description

Bytel is a mobile telephony potentate. Each employee has been issued a company phone, the memory ofwhich holds the numbers of some of his co-workers (all of them have his number in their phones as well).

Due to dynamic growth of their operations the board of directors intends to move company headquaters tonew office buildings. It has been decided - in order to boost work efficiency - that every pair of employeesworking in different buildings should know (reciprocally) each others phone number i.e. the memory of theircompany phone ought to hold necessary phone numbers.

Simultaneously, the board have decided to rent as many office buildings as possible to ensure good workingconditions. Help the board of Bytel to plan the number of office buildings and their size in accordancewith the aforementioned requirements.

TaskWrite a programme which:

reads the description of employees‘ phone number lists from the standard input calculates the maximal number of office buildings and their sizes, satisfying board‘s conditions writes the outcome to the standard output.

input

The first line of the standard input consists of two integers:  and (),separated by single spaces, denoting the number of Bytel employees and the number of pairs of employeeswho have their numbers in company phones, respectively. The employees are numbered from  to .

Each of the following  lines contains a single pair of integers  and ( for ), separated by a single space, denoting that employees!

output

The first line of the standard output should contain a single integer: the maximal number of office buildingsthat Bytel should rent. The second should contain a non-decreasing sequence of positive integers, separatedby singe spaces, denoting the sizes of the office buildings (i.e. the numbers of employees working there).

Should there exist more than one correct answer - write out any one of them.

给出一个图(N个点,M条边),让你把此图分成尽可能多的集合,满足任意不在同一集合的点之间都有边相连。

简化为:求反图的联通块个数

那么可以这样考虑,将每个点转换成链表

将联通块求出来,同时不断用与当前节点在原图有连边的节点加入新链表,统计剩余列表并加入至队列

再用新链表代替老链表,反复进行即可

#include<cstdio>
#include<queue>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cctype>
using namespace std;
const int N=1000010,M=2000010;
int read(){
    char c;int x=0,f=1;
    for(c=getchar();!isdigit(c);c=getchar())if(c==‘-‘)f=-1;
    for(;isdigit(c);c=getchar())x=(x<<3)+(x<<1)+(c^48);
    return x*f;
}
vector<int> G[N];
queue<int> Q;
int ans[N],pr[N],ne[N];
bool in[N];
int tot,sum;
int n,m;
void add(int x,int y){
    ne[y]=ne[x];
    if(ne[x])pr[ne[x]]=y;
    ne[x]=y;pr[y]=x;
}
void del(int x){
    if(pr[x])ne[pr[x]]=ne[x];
    if(ne[x])pr[ne[x]]=pr[x];
}
void BFS(){
    while(!Q.empty())Q.pop();
    Q.push(ne[n+1]);
    in[ne[n+1]]=false;del(ne[n+1]);
    ++tot;
    while(!Q.empty()){
        int u=Q.front();
        ++sum;++ans[tot];
        Q.pop();
        pr[n+2]=ne[n+2]=0;
        for(int i=0,i_end=G[u].size();i<i_end;++i){
            int v=G[u][i];
            if(!in[v])continue;
            del(v);//delete it
            add(n+2,v);//add in new list
        }
        for(int i=ne[n+1];i;i=ne[i]){
            Q.push(i);
            in[i]=false;
        }
        ne[n+1]=ne[n+2];
        pr[ne[n+1]]=n+1;
        //ls list takeplace last list
    }

}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    tot=0,sum=0;
    for(int i=1;i<=n;++i)add(n+1,i);
    for(int i=1;i<=n;++i)in[i]=true;
    while(sum<n)BFS();
    printf("%d\n",tot);
    sort(ans+1,ans+1+tot);
    for(int i=1;i<=tot;++i)
        printf("%d ",ans[i]);
    return 0;
}

这让我想起了APIO2007的数据备份,可以多多写一写链表的优化

时间: 2024-10-07 03:13:17

BZOJ 1098 [POI2007]办公楼biu 链表的相关文章

bzoj 1098 [POI2007]办公楼biu bfs+补图+双向链表

[POI2007]办公楼biu Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1543  Solved: 743[Submit][Status][Discuss] Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一些新的办公楼.FGD希望职员被安置在尽量多的办公楼当中,这样对于每个职员

[BZOJ 1098] [POI2007] 办公楼biu 【链表优化BFS】

题目链接:BZOJ - 1098 题目分析 只有两个点之间有边的时候它们才能在不同的楼内,那么就是说如果两个点之间没有边它们就一定在同一座楼内. 那么要求的就是求原图的补图的连通块. 然而原图的补图的边数是 n^2 级别的,非常庞大,我们不能直接把补图求出来. 可以使用一种用链表优化BFS的做法,开始时将所有的点加到一个链表里. 每次找一个连通块的时候BFS,在链表中取出一个点,在链表中删除,加入队列,然后每次取出队首元素x,枚举x的每一条边,将边的终点y从链表中删去,加到一个临时的链表中存储.

bzoj 1098 [POI2007] 办公楼 biu

# 解题思路 画画图可以发现,只要是两个点之间没有相互连边,那么就必须将这两个人安排到同一个办公楼内,如图所示: 那,我们可以建立补图,就是先建一张完全图,然后把题目中给出的边都删掉,这就是一张补图,显然补图中相互连边的点就放在同一栋办公楼内. 我们可以用并查集来完成,但是数据范围显然不允许用这样的方法,建图的复杂度是 $N^2$ 的.所以考虑另一种方法: 将原图建立好,在原图中,从一个点开始,把这个点所能够直接到达的点标记出来,这些点是不可以放在一起的.然后将这些点删除. 之后对每一个点都进行

BZOJ 1098[POI2007]办公楼

题面: 1098: [POI2007]办公楼biu Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1371  Solved: 641[Submit][Status][Discuss] Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一些新的办公楼.FGD希望职员被安置在尽量多的办公楼当

BZOJ1098: [POI2007]办公楼biu

1098: [POI2007]办公楼biu Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 777  Solved: 326[Submit][Status] Description FGD开办了一家电话公司.他雇用了N个职员,给了每个职员一部手机.每个职员的手机里都存储有一些同事的电话号码.由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一些新的办公楼. FGD希望职员被安置在尽量多的办公楼当中,这样对于每个职员来说都

【BZOJ1098】[POI2007]办公楼biu

题目一开始看以为和强联通分量有关,后来发现是无向边,其实就是求原图的补图的联通块个数和大小.学习了黄学长的代码,利用链表来优化,其实就是枚举每一个人,然后把和他不相连的人都删去放进同一个联通块里,利用bfs来实现.——by VANE #include<bits/stdc++.h> using namespace std; const int N=100005; const int M=4000005; struct edge{int to,next;}e[M]; int a[N],q[N];

BZOJ1098 办公楼biu (BFS+链表优化)

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1098分析:见注释. 1 // 补图连通块 bfs + 链表优化 2 #include <cstdio> 3 #include <queue> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 8 struct Edge { 9 int to, nxt; 10 }; 11

bzoj 1588 [HNOI2002] 营业额统计 链表和Splay

来自HNOI 2002营业额的统计一题,这题以前是用链表水过的,最近看见许多splay的题,赶紧张一下知识. 题目大意就是对于一个序列,输出每个元素与它之前元素的差的最小值的和.先说链表的方法吧. 大概就是sort一下,记录每个点的rank.然后链表一下,很好理解,复杂度nlogn,瓶颈在于排序. #include<cstdio> #include<algorithm> #include<iostream> using namespace std; struct nod

bzoj 1101 [POI2007]Zap - 莫比乌斯反演

Description FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a ,y<=b,并且gcd(x,y)=d.作为FGD的同学,FGD希望得到你的帮助. Input 第一行包含一个正整数n,表示一共有n组询问.(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个 正整数,分别为a,b,d.(1<=d<=a,b<=50000) Output 对于每组询问,输出到输出文件zap.out一个正