题解 CF70E【Information Reform】
题目描述
\(n\) 个点的树,边权为 \(1\)。可以花费常数 \(k\),在一个点上建基站。每个点 \(i\) 需要找到离他最近的基站 \(a_i\),花费 \(d[dis(i, a_i)]\)。一种方案的总花费是建基站的花费加上每个点的花费之和。最小化总花费。输出方案 \(a_i\)。数组 \(d\) 单调不降,\(d_0=0\)。\(n\leq 180\)。
solution
设 \(f(u, x)\) 表示考虑完了点 \(u\) 的子树中所有点的花费,点 \(u\) 找到的 \(a_u=x\),注意 \(x\) 这个基站的花费已经计算。转移枚举儿子 \(v\) 用哪个基站,用它自己的 \(a_v\) 还是 \(x\):
\[f(u, x)=d[dis(u, x)]+k+\sum_{v\in son(u)}\min(f(v, x)-k, f(v, a_v)) \]\(f(v, x)-k\) 就是用基站 \(x\),\(-k\) 是为了不和外面的 \(+k\) 重复计算;\(f(v, a_v)\) 就是用 \(v\) 自己的基站。算完以后,\(a_u\) 就是 \(\arg\min_xf(u, x)\)。
对于输出的方案,重新自顶向下 dfs 一遍。看一看是 \(f(v, a_u)-k\) 更优还是 \(f(v, a_v)\) 更优,如果前者更优,说明 \(v\) 要用基站 \(a_u\),将 \(a_v\) 篡改为 \(a_u\),然后向 \(v\) 搜索。
code
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
int n, k, d[210], dis[210][210], g[210], ans[210];
LL f[210][210];
void floyed(int k) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
void dfs(int u, int fa = 0) {
for (int v = 1; v <= n; v++)
if (dis[u][v] == 1 && v != fa) {
dfs(v, u);
for (int x = 1; x <= n; x++) f[u][x] += min(f[v][x] - k, f[v][g[v]]);
}
for (int x = 1; x <= n; x++) f[u][x] += d[dis[u][x]] + k;
g[u] = u;
for (int x = 1; x <= n; x++)
if (f[u][x] < f[u][g[u]]) g[u] = x;
}
void research(int u, int fa = 0) {
int x = ans[u] = g[u];
for (int v = 1; v <= n; v++)
if (dis[u][v] == 1 && v != fa) {
if (f[v][x] - k < f[v][g[v]]) g[v] = x;
research(v, u);
}
}
int main() {
// #ifdef LOCAL
// freopen("input.in","r",stdin);
// #endif
memset(dis, 0x3f, sizeof dis);
scanf("%d%d", &n, &k);
for (int i = 1; i < n; i++) scanf("%d", &d[i]);
for (int i = 1, u, v; i < n; i++)
scanf("%d%d", &u, &v), dis[u][v] = dis[v][u] = 1;
for (int i = 1; i <= n; i++) dis[i][i] = 0;
for (int i = 1; i <= n; i++) floyed(i);
dfs(1), printf("%lld\n", f[1][g[1]]), research(1);
for (int i = 1; i <= n; i++) printf("%d%c", ans[i], " \n"[i == n]);
return 0;
}
标签:210,Reform,花费,题解,基站,CF70E,include,dis
From: https://www.cnblogs.com/caijianhong/p/18105633/solution-CF70E