首页 > 其他分享 >题解 CF70E【Information Reform】

题解 CF70E【Information Reform】

时间:2024-03-30 16:11:36浏览次数:28  
标签:210 Reform 花费 题解 基站 CF70E include dis

题解 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

相关文章

  • ICPC2023 陕西邀请赛 题解
    G-PermutationQuestion找到一个排列\(p\),使得\(\prod_{i=1}^nlcm(p_i,p_{(imodn)+1})\)最大Solution考虑到\(x\)和\(x-1\)必然是互质的所以顺序排列即可Code#include<bits/stdc++.h>usingnamespacestd;intmain(){intn;cin>>n;for(inti......
  • 快递员的烦恼【华为OD机试JAVA&Python&C++&JS题解】
    一.题目-快递员的烦恼快递公司每日早晨,给每位快递员推送需要送到客户手中的快递以及路线信息,快递员自己又查找了一些客户与客户之间的路线距离信息,请你依据这些信息,给快递员设计一条最短路径,告诉他最短路径的距离。注意:不限制快递包裹送到客户手中的顺序,但必须保证都送......
  • 园区参观路径【华为OD机试JAVA&Python&C++&JS题解】
    一.题目-园区参观路径园区某部门举办了FamilyDay,邀请员工及其家属参加;将公司园区视为一个矩形,起始园区设置在左上角,终点园区设置在右下角;家属参观园区时,只能向右和向下园区前进;求从起始园区到终点园区会有多少条不同的参观路径;输入描述:第一行为园区长和宽;后面每一行表示......
  • [题解]P1439 【模板】最长公共子序列
    P1439【模板】最长公共子序列题意简述给出\(1,2,…,n\)的两个排列\(P_1\)和\(P_2\),求它们的最长公共子序列。范围限制:\(n\le10^5\)。样例53214512345输出:3。思路简述这道题看似是最长公共子序列,但是发现如果用\(O(n^2)\)的复杂度实现\(LCS\)就会时......
  • 2024年03月CCF-GESP编程能力等级认证C++编程八级真题解析
    本文收录于专栏《C++等级认证CCF-GESP真题解析》,专栏总目录:点这里。订阅后可阅读专栏内所有文章。一、单选题(每题2分,共30分)第1题为丰富食堂菜谱,炒菜部进行头脑风暴。肉类有鸡肉、牛肉、羊肉、猪肉4种,切法有肉排、肉块、肉末3种,配菜有圆白菜、油菜、豆腐3种,辣度有......
  • 2024年03月CCF-GESP编程能力等级认证C++编程七级真题解析
    本文收录于专栏《C++等级认证CCF-GESP真题解析》,专栏总目录:点这里。订阅后可阅读专栏内所有文章。一、单选题(每题2分,共30分)第1题下列关于排序的说法,正确的是()。A.冒泡排序是最快的排序算法之一。B.快速排序通常是不稳定的。C.最差情况,N个元素做归并排序......
  • ccfcsp-2019-12-2回收站选址(c++满分题解)
    该题就是考察点的保存以及索引的保存和遍历,看了他的用例说明,我原先以为暴力只能得50分,但是又没有想到别的优化方法,就写了一下暴力,发现居然AC下面是代码:#include<iostream>#include<vector>#include<map>usingnamespacestd;intmain(){ intn; cin>>n; vector<pair<......
  • atcoder beginner 346 题解
      看到别人的视频讲解 AtCoderBeginnerContest346A至G題讲解bydreamoon C如果用sort写,那么再从小到大遍历也需要写几行#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<cstdbool>#include<string>#include<......
  • P1484 种树 题解
    P1484种树有\(n\)个坑。第\(i\)个坑种树的价值是\(c_i\),相邻坑不能同时种。可以种\(k\)颗树,求最大价值。模拟费用流,建图类似这样:中间两层结点之间有\(7\)条边,表示\(n=7\)的情况。相邻两条边,例如\(1,2\)总流入量为\(1\),\(2,3\)总流出量为\(1\),也不可能出现相......
  • Luogu P6834 梦原 题解
    原题传送门首先考虑如果树的形态确定了之后的情况:如果当前点比爸爸的值大,那么显然爸爸变成\(0\)之后,这个点需要自己被额外操作删除,贡献就是\(a[v]-a[u]\)。类似,如果比爸爸的值小,那么这个点肯定会跟爸爸一起被删除,所以贡献就是\(0\)。综上所述,一个点的贡献是\(max{a[v]-......