题目大意:无向图中给定n个顶点,m条不存在的边(除了这m条边,其余都存在),求图的连通分量,及每个连通分量的大小。
list < int > g;存储1~n个顶点。再后续的操作中将其分裂成若干块,直到list为空。
(1)当list不为空,清空队列,取队首的一个点入队。
(2)当queue不为空,取一个点,将与其相关的点入队并从list中删除。记录联通块大小。
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <list>
using namespace std;
const int N = 2e5+10;
bool vis[N];
vector <int> a[N], ans;
list <int> g;//用vector超时
list <int>:: iterator it, tmp;
int n, m;
int main()
{
scanf("%d %d", &n, &m);
int x, y;
for(int i = 1; i <= m; ++i)
{
scanf("%d %d", &x, &y);
a[x].push_back(y);
a[y].push_back(x);
}
for(int i = 1; i <= n; ++i) g.push_back(i);//分裂g成若干个联通块
while(!g.empty())//一次得到一个联通块,直到分裂完毕即为空
{
ans.push_back(1);
queue <int> q;
it = g.begin();
q.push((*it));
g.erase(it);//分裂
while(!q.empty())//用入队的点继续扩展
{
memset(vis, 0, sizeof(vis));
int u = q.front();
q.pop();
for(int i = 0; i < a[u].size(); ++i)
vis[a[u][i]] = 1;//标记于u无关的点
for(it = g.begin(); it != g.end();)
if(!vis[(*it)])//与u有关的点
{
++ans.back();
q.push((*it));
tmp = it;
++it;//先++再删点
g.erase(tmp);//分裂
}
else ++it;//
}
}
sort(ans.begin(), ans.end());
printf("%d\n", ans.size());
printf("%d", ans[0]);
for(int i = 1; i < ans.size(); ++i)
printf(" %d", ans[i]);
printf("\n");
return 0;
}