题面
解法
思路比较清晰的构造题
- 感觉这道题并不能准确说是一个贪心,但是好像用了贪心的思想
- 因为多个省可以共用省会,所以我们可以考虑尽量将一个点作为多个省会
- 因为题目并没有要求使最后的省个数尽量小,所以我们可以这样构造:只要出现一组合法的省,直接把这个省单独立出来
- 那么,问题就转化成如何找一个合法的省。可以发现,我们可以尽量让一棵子树的根作为省会,因为这样一定能保证这个省是合法的。
- 所以,现在我们就得到了一个大致的算法:假设当前dfs到点 ,先分 的儿子,如果存在可以直接把儿子的子树变成一个省的情况,直接将 变成省会,那些可以作为一个省的点直接被删掉,如此做即可。
- 然后,我们考虑为什么这样一定可以满足省内的点
- 显然,每一次只要出现一个大小不小于 的省就直接划分,如果出现一个省大小超过了 ,那么就一定可以在它大小不小于 的时候直接被划分出来,所以这样就可以保证这个算法是正确的
- 时间复杂度:
代码
#include <bits/stdc++.h>
#define N 1010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Edge {
int next, num;
} e[N * 3];
int n, b, l, cnt, tot, st[N], siz[N], col[N], ans[N];
void add(int x, int y) {
e[++cnt] = (Edge) {e[x].next, y};
e[x].next = cnt;
}
void dfs(int x, int fa) {
st[++l] = x;
for (int p = e[x].next; p; p = e[p].next) {
int k = e[p].num;
if (k == fa) continue; dfs(k, x);
if (siz[x] + siz[k] >= b) {
ans[++tot] = x, siz[x] = 0;
while (st[l] != x) col[st[l--]] = tot;
} else siz[x] += siz[k];
}
siz[x]++;
}
void update(int x, int fa, int c) {
if (col[x]) c = col[x]; else col[x] = c;
for (int p = e[x].next; p; p = e[p].next)
if (e[p].num != fa) update(e[p].num, x, c);
}
int main() {
read(n), read(b); cnt = n;
for (int i = 1; i < n; i++) {
int x, y; read(x), read(y);
add(x, y), add(y, x);
}
if (n < b) return cout << "0\n", 0;
dfs(1, 0); if (!tot) tot++;
col[1] = tot; update(1, 0, col[1]); cout << tot << "\n";
for (int i = 1; i <= n; i++) cout << col[i] << ' '; cout << "\n";
for (int i = 1; i <= tot; i++) cout << ans[i] << ' '; cout << "\n";
return 0;
}