- 题目链接:http://codeforces.com/contest/920/problem/E
- 题意:给你n个点,m条边,这个由n个点组成的图中,除了给你的m条边不存在以外,其他边都存在,两点间只有一条边,且无自环。
- 算法:BFS
- 思路:因为1 ≤ n ≤ 200000,所以用无法用邻接表存图,可以用二维的map代替二维数组(当然,既然算法是BFS的话,用前向星之类的也行)。
- 把1~n放入一个点集,
- 从一个点开始BFS,找出所有与该点连在一起的点,并把这些点从点集中删去,同时记录下他们的个数。循环这一步操作,直到点集为空。
- 坑点:这题看起来用set比较简单,但是set在寻找连通点的时候太麻烦
- 删去已经找到的点后,如何让迭代器获得新的点的位置?毕竟将当前点删去后,迭代器指向的当前点的值。如果用upper_bound()更新的话,如果当前点是set中最后一个值的话又会出问题。所以本文用的是vector
#include <bits/stdc++.h>
#define pi acos(-1)
#define fastcin ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const LL ll_INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 200000 + 10;
const int mod = 1e9 + 7;
map<int, bool> mp[maxn];
vector<int> vec, ans;
int BFS(int x)
{
queue<int> Q;
Q.push(x);
int cnt=0;
while(!Q.empty()){
int u = Q.front(); Q.pop();
cnt++;
for(int i=0; i<vec.size(); i++){
x = vec[i];
if(!mp[u][x]){
Q.push(vec[i]);
swap(vec[i], vec.back()); vec.pop_back();
i--;
}
}
}
return cnt;
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for(int i=0; i<m; i++){
int x,y;
scanf("%d%d", &x, &y);
mp[x][y]=1;
mp[y][x]=1;
}
for(int i=1; i<=n; i++) vec.push_back(i);
while(!vec.empty()){
int x = vec.back(); vec.pop_back();
int each = BFS(x);
if(each) ans.push_back(each);
}
sort(ans.begin(), ans.end());
printf("%d\n", ans.size());
for(int i=0; i<ans.size(); i++){
printf("%d%c", ans[i], " \n"[i==ans.size()-1]);
}
}