BZOJ1098 [POI2007]办公楼biu
1098: [POI2007]办公楼biu
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 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
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
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 }