【POI 2007】Office 办公楼(BIU)
http://www.zybbs.org/JudgeOnline/problem.php?id=1098
题目大意:给定一个N个点M条边的无向图,将N个点分成尽量多的组,满足任意两个不在同一组的点之间都有边。
此题的答案就是原图补图的联通块个数。具体在WC2011 MT的课件中有。
原话是:将未访问点挂链,扩展一个点时,标记原图中该点的相邻点,遍历链表,将所有未标记点(即该点在补图中的邻居)入队并从链表中删除。
然后我就根据这个很笨拙地串了一条链……
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>
#define mm 2000100
#define mn 100003
using namespace std;
queue<int> q;
vector<int> v;
int n,m,a,b,ans;
bool vis[mn];
struct EDGE{
int pnt;
EDGE *pre;
EDGE(){}
EDGE(int _pnt,EDGE *_pre):pnt(_pnt),pre(_pre){}
}Edge[mm*2],*SP=Edge,*edge[mm];
struct LINE{
int pre,next;
bool flag;
}line[mn];
inline void addedge(int a,int b){
edge[a]=new(++SP)EDGE(b,edge[a]);
edge[b]=new(++SP)EDGE(a,edge[b]);
}
void Del(int i){
line[line[i].next].pre=line[i].pre;
line[line[i].pre].next=line[i].next;
}
void bfs(){
while(line[0].next!=-1){
q.push(line[0].next);
vis[line[0].next]=true;
Del(line[0].next);
int cnt=1;
while(!q.empty()){
int i=q.front();q.pop();
for(EDGE *j=edge[i];j;j=j->pre) line[j->pnt].flag=true;
for(int j=line[0].next;j>0;j=line[j].next)
if(!line[j].flag && !vis[j]){
q.push(j);
vis[j]=true;
Del(j);
cnt++;
}
for(int j=line[0].next;j>0;j=line[j].next) line[j].flag=false;
}
ans++;
v.push_back(cnt);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
addedge(a,b);
}
for(int i=1;i<=n;i++)
line[i-1].next=i,line[i].pre=i-1;
line[n].next=-1;
bfs();
sort(v.begin(),v.end());
printf("%d\n",ans);
if(!v.empty()){
for(int i=0;i<v.size()-1;i++) printf("%d ",v[i]);
printf("%d\n",v[v.size()-1]);
}
return 0;
}

浙公网安备 33010602011771号