Skip to content
本博客自 2023 年 4 月 4 日起转为归档状态,可能不再发表新的博文。点此了解博主的竞赛生涯
This blog has been archived by the owner since April 4, 2023. It may no longer have new updates.

「POI2007」Offices

检测到 KaTeX 加载失败,可能会导致文中的数学公式无法正常渲染。

#题面

#题目描述

Bytel 是一家移动通信公司。该公司的每位员工都收到了一部公司生产的电话,电话的通讯录中存储着一些同事的电话号码(每部手机中也都有该手机本身的电话号码)。

由于业务扩张,公司总部需要迁移至新的办公区。为了提高工作效率,董事会决定在不同栋楼工作的每一对员工需要 相互 知道对方的电话号码。即如果 uuvv 在不同的楼工作,则 uu 的通讯录里需要存储 vv 的电话号,vv 的通讯录里也要存储 uu 的电话号码。

同时,董事会决定租用尽可能多的楼,以确保良好的工作条件。现在你需要帮助 Bytel 公司计算出他们需要租用多少栋楼。

#输入格式

输入第一行包含两个整数 n,mn, m,分别代表公司的员工数和通讯录的信息数,员工从 11nn 编号。

接下来 mm 行,每行两个整数 ai,bia_i, b_i,表示 aia_ibib_i 相互 知道对方的电话号码,保证任意两条信息不重复。

#输出格式

输出第一行包含一个整数 tt:董事会需要租用多少栋办公楼。

第二行包含 tt 个整数,第 ii 个整数 cic_i 表示在第 ii 栋建筑工作的员工数量。你的输出需要保证 cic_i 是单调不下降的。

如果有多种合法方案,你可以输出任意一种。

#样例输入输出

样例输入 #1

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 2 4

#数据范围与约定

对于 100%100\% 的数据,2n1052 \leq n \leq 10^51m2×1061 \leq m \leq 2 \times 10^61ai<bin1 \leq a_i \lt b_i \leq n

#思路

给定一张 nn 个点 mm 条边的图,求出其补图的连通块个数以及各个连通块的大小。

使用 BFS 搜索答案,开一个 set 记录未划分的点。对于每个 uu 遍历一遍整个 set,如果 set 中的某个点 vv 不能从 uu 出发直接到达(即不存在一条 uvu \to v 的边),那么点 vv 就和点 uu 在补图中位于同一个连通块内。

#代码

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>

using std::cin;
using std::cout;
const char endl = '\n';

const int N = 1e5 + 5;

int n, m, cnt, ans[N];
std::vector<int> g[N];
std::set<int> set;
bool vis[N];

void bfs(int x) {
std::queue<int> q;

set.erase(x);
q.push(x);
ans[cnt]++;

while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = true;

for (auto it = set.begin(); it != set.end();) {
int v = *it;

if (*std::lower_bound(g[u].begin(), g[u].end(), v) != v) {
q.push(v);
ans[cnt]++;
set.erase(it++);
} else {
it++;
}
}
}
}

int main() {
std::ios::sync_with_stdio(false);
cin.tie(nullptr);

cin >> n >> m;

for (int i = 1, u, v; i <= m; i++) {
cin >> u >> v;

g[u].push_back(v);
g[v].push_back(u);
}

std::for_each(g + 1, g + n + 1, [&](auto& v) {
std::sort(v.begin(), v.end());
});

for (int i = 1; i <= n; i++) {
set.insert(i);
}

for (int i = 1; i <= n; i++) {
if (!vis[i]) {
cnt++;
bfs(i);
}
}

std::sort(ans + 1, ans + 1 + cnt);

cout << cnt << endl;

for (int i = 1; i <= cnt; i++) {
cout << ans[i] << ' ';
}

cout << endl;

return 0;
}