BZOJ1098 [POI2007]办公楼biu

1098: [POI2007]办公楼biu

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 1653  Solved: 810
[Submit][Status][Discuss]

Description

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

Input

  第一行包含两个整数N(2<=N<=100000)和M(1<=M<=2000000)。职员被依次编号为1,2,……,N.以下M行,每
行包含两个正数A和B(1<=A<b<=n),表示职员a和b拥有彼此的电话号码),li <= 1000

Output

  包含两行。第一行包含一个数S,表示FGD最多可以将职员安置进的办公楼数。第二行包含S个从小到大排列的
数,每个数后面接一个空格,表示每个办公楼里安排的职员数。

Sample Input

7 16
1 3
1 4
1 5
2 3
3 4
4 5
4 7
4 6
5 6
6 7
2 4
2 7
2 5
3 5
3 7
1 7

Sample Output

3
1 2 4

HINT

 

FGD可以将职员4安排进一号办公楼,职员5和职员7安排进2号办公楼,其他人进3号办公楼。

 

题解:

如果两个人彼此间没有连边,则两个人必须在同一栋楼中,可以看出是求补图的连通块个数。

用链表维护未访问过的集合,每次从未访问过的点中选择一个点,先把该点从集合中删去,然后通过给所有与该点相连的点打上标记,找到未访问集合中所有未与该点相连的点(即与该点在统一大楼的点),通过bfs即可找到补图中该点所在连通块内的所有点。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 100005;
 4 const int M = 2000005;
 5 struct Edge{
 6     int to,next;
 7 }edge[M*2];
 8 int n,m,ans,tol;
 9 int head[N],next[N],pre[N],a[N],vis[N];
10 
11 void del(int x){
12     next[pre[x]] = next[x];
13     pre[next[x]] = pre[x];
14 }
15 
16 void addedge(int u,int v){
17     edge[tol] = Edge{v,head[u]};
18     head[u] = tol++;
19 }
20 
21 void bfs(int x){
22     queue<int>q;
23     q.push(x);
24     memset(vis,0,sizeof(vis));
25     while(!q.empty()){
26         int u = q.front();
27         a[ans]++;
28         q.pop();
29         vis[u] = 1;
30         for (int i = head[u];i != -1;i = edge[i].next){
31             int v = edge[i].to;
32             vis[v] = 1;
33         }
34         for (int i = next[0];i <= n; i = next[i]){
35             if (!vis[i]) del(i),q.push(i);
36         }
37         for (int i = head[u];i != -1;i = edge[i].next){
38             int v = edge[i].to;
39             vis[v] = 0;
40         }
41     }
42 }
43 
44 int main()
45 {
46     tol = 0;
47     memset(head,-1,sizeof(head));
48     memset(a,0,sizeof(a));
49     scanf("%d%d",&n,&m);
50     for (int i = 0;i <= n;++i) pre[i] = i-1,next[i] = i+1;
51     for (int i = 0;i < m;++i){
52         int u,v;
53         scanf("%d%d",&u,&v);
54         addedge(u,v);
55         addedge(v,u);
56     }
57     ans = 0;
58     for (int i = next[0];i <= n;i = next[0]){
59         del(i);
60         bfs(i);
61         ans++;
62     }
63     sort(a,a+ans);
64     printf("%d\n",ans);
65     for (int i = 0;i < ans;++i) printf("%d%c",a[i]," \n"[i == ans-1]);
66 }

 

如果用set维护未访问集合会RE

 1 /**************************************************************
 2     Problem: 1098
 3     User: mizersy
 4     Language: C++
 5     Result: Runtime_Error
 6 ****************************************************************/
 7  
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 const int N = 100005;
11 const int M = 2000005;
12 struct Edge{
13     int to,next;
14 }edge[M*2];
15 int n,m,ans,tol;
16 int head[N],next[N],pre[N],a[N],vis[N];
17 set <int> s;
18 void addedge(int u,int v){
19     edge[tol] = Edge{v,head[u]};
20     head[u] = tol++;
21 }
22  
23 void bfs(int x){
24     queue<int>q;
25     q.push(x);
26     memset(vis,0,sizeof(vis));
27     while(!q.empty()){
28         int u = q.front();
29         a[ans]++;
30         q.pop();
31         vis[u] = 1;
32         for (int i = head[u];i != -1;i = edge[i].next){
33             int v = edge[i].to;
34             vis[v] = 1;
35         }
36  
37         for (set<int>::iterator it = s.begin();it != s.end();it++){
38             if (!vis[*it]) s.erase(*it),q.push(*it);
39         }
40         for (int i = head[u];i != -1;i = edge[i].next){
41             int v = edge[i].to;
42             vis[v] = 0;
43         }
44     }
45 }
46  
47 int main()
48 {
49     tol = 0;
50     memset(head,-1,sizeof(head));
51     memset(a,0,sizeof(a));
52     scanf("%d%d",&n,&m);
53     for (int i = 1;i <= n;++i) s.insert(i);
54     for (int i = 0;i < m;++i){
55         int u,v;
56         scanf("%d%d",&u,&v);
57         addedge(u,v);
58         addedge(v,u);
59     }
60     ans = 0;
61  
62     for (set<int>::iterator it = s.begin();it != s.end();it = s.begin()){
63         s.erase(*it);
64         bfs(*it);
65         ans++;
66     }
67     sort(a,a+ans);
68     printf("%d\n",ans);
69     for (int i = 0;i < ans;++i) printf("%d%c",a[i]," \n"[i == ans-1]);
70 }
View Code

 

posted @ 2018-08-30 21:18  mizersy  阅读(316)  评论(0编辑  收藏  举报