题解:P16442 [XJTUPC 2026] 机房分配
官方题解里说的比较清楚,也就是每次分配时取风险增加量的最小值,每次增加量不会超过它与所有其他边全值的平均值。
这里给一个比较抽象的概率上的理解,现在假设所有同学都是随机分机房的,考虑
假设
因此对
因此一定存在不比期望高的分配方案,故存在一种方案使得风险值之和不超过
只需要贪心地每次选择风险值最小的那一组分配即可。参考代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
int num = 0, nev = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') nev = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { num = num * 10 + (ch - '0'); ch = getchar(); }
return num * nev;
}
struct edge{
int to, w;
};
struct node{
int g, w; //分组,权值
};
int cmp(const node &a, const node &b) {
return a.g < b.g;
}
const int maxn = 5e5 + 5;
vector<edge> G[maxn];
int group[maxn];
signed main() {
int n = read(), m = read(), k = read();
for (int i = 1; i <= m; i ++) {
int u = read(), v = read(), w = read();
G[u].push_back((edge){v, w});
G[v].push_back((edge){u, w});
}
for (int u = 1; u <= n; u ++) {
vector<node> nei; //与u存在边的近邻
for (edge e : G[u]) {
int v = e.to;
int w = e.w;
if (group[v]) {
nei.push_back((node){group[v], w});
}
}
sort(nei.begin(), nei.end(), cmp);
vector<node> tmp; //对nei进行去重,相同组的合并
for (int i = 0; i < nei.size(); i ++) {
if (i == 0 || nei[i].g != nei[i-1].g) {
tmp.push_back(nei[i]);
} else {
tmp.back().w += nei[i].w;
}
}
if (tmp.size() == k) { //如果与u相邻的点都已经分好组且没有其它组可分
int minc = 1e17, gr = 0;
for (int i = 0; i < tmp.size(); i ++) {
if (tmp[i].w < minc) {
minc = tmp[i].w;
gr = tmp[i].g;
}
}
group[u] = gr;
} else {
int cur = 1;
for (int i = 0; i < tmp.size(); i ++) {
if (cur < tmp[i].g) break;
else cur = tmp[i].g + 1;
}
group[u] = cur;
}
}
puts("Yes");
for (int i = 1; i <= n; i ++) {
cout << group[i] << ' ';
}
return 0;
}