Description
FGD开办了一家电话公司。他雇用了N个职员,给了每个职员一部手机。每个职员的手机里都存储有一些同事的电话号码。由于FGD的公司规模不断扩大,旧的办公楼已经显得十分狭窄,FGD决定将公司迁至一些新的办公楼。 FGD希望职员被安置在尽量多的办公楼当中,这样对于每个职员来说都会有一个相对更好的工作环境。但是,为了联系方便起见,如果两个职员被安置在两个不同的办公楼之内,他们必须拥有彼此的电话号码。
Input
第一行包含两个整数N(2<=N<=100000)和M(1<=M<=2000000)。职员被依次编号为1,2,……,N. 以下M行,每行包含两个正数A和B(1<=A
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就可以了
可是这样会超时。
怎么办?在bfs遍历点的时候链表优化!
走过的点就可以不再查询是否与当前点的补图连边
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
struct line
{
int s,t;
int next;
}a[4000001];
int head[100001];
int edge;
inline void add(int s,int t)
{
a[edge].next=head[s];
head[s]=edge;
a[edge].s=s;
a[edge].t=t;
}
struct point
{
int next;
int pre;
}l[100001];
queue <int> Q;
int ss;
int ans[100001];
bool v[100001],vx[100001];
inline void del(int i)
{
l[l[i].pre].next=l[i].next;
l[l[i].next].pre=l[i].pre;
}
inline void bfs()
{
int i;
while(l[0].next!=0)
{
int d=l[0].next;
del(d);
Q.push(d);
v[d]=true;
int s=1;
while(!Q.empty())
{
d=Q.front();
Q.pop();
for(i=head[d];i!=0;i=a[i].next)
vx[a[i].t]=true;
for(i=l[0].next;i!=0;i=l[i].next)
{
if(!v[i]&&!vx[i])
{
s++;
v[i]=true;
Q.push(i);
del(i);
}
}
for(i=head[d];i!=0;i=a[i].next)
vx[a[i].t]=false;
}
ss++;
ans[ss]=s;
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int i;
int s,t;
for(i=1;i<=m;i++)
{
scanf("%d%d",&s,&t);
edge++;
add(s,t);
edge++;
add(t,s);
}
l[0].next=1;
for(i=1;i<=n;i++)
{
l[i].pre=i-1;
l[i].next=i+1;
}
l[n].next=0;
bfs();
printf("%d\n",ss);
sort(ans+1,ans+1+ss);
for(i=1;i<=ss;i++)
printf("%d ",ans[i]);
// printf("%d\n",ans[i]);
return 0;
}