树形dp ---- gym101667 A(贪心 + 树形dp + 两个dp方程组维护)

news/2024/6/28 18:07:02

题目链接


题目大意:

就是一棵5e35e35e3的树,可以选择一些点,放上基站,如果uuu上的基站价值为ddd,那么距离uuu小于等于ddd的点都会被覆盖,问使得整棵树被覆盖需要的最小价值。


解题思路:

  1. 一开始我是这么想树形dp的 dp[i][j]表示覆盖完i子树并且i节点放置权值为j的覆盖站的所需要的最小价值dp[i][j]表示覆盖完i子树并且i节点放置权值为j的覆盖站的所需要的最小价值dp[i][j]iij

  2. 但是这里有两个问题就是如果你是有根树:你每个点的放置一个权值为www的信号站,不仅会覆盖到儿子节点,也会覆盖到祖先节点,这样dpdpdp不容易实现,因为你不知道它向上影响了多远

  3. 那么我们为什么不把那个影响距离带到dpdpdp方程里面去呢?

  4. dp[u][j]表示覆盖完u这个子树并且能够覆盖到所有向上距离它≤j所有点的最小代价是多少?dp[u][j]表示覆盖完u这个子树并且能够覆盖到所有向上距离它\leq j所有点的最小代价是多少?dp[u][j]uj

  5. 那么我们知道向上影响距离是jjj无非两种情况就是
    (1):在u这个位置直接放置权值为jjj的基站
    (2):子树传递影响上去

  6. 对于子树直接放置权值为jjj的基站我们知道它的影响是两个方向的有儿子也有祖先:那么根据贪心原理dp[u][j]=j+g[u][j+1],g[u][j+1]:覆盖距离u距离≥j的所有dp[u][j]=j+g[u][j+1],g[u][j+1]:覆盖距离u距离\ge j的所有dp[u][j]=j+g[u][j+1]g[u][j+1]:uj儿子节点所需要的最小代价(注意这里是只有儿子)

  7. 如果是子树传递上去的呢?
    dp[u][j]=min{dp[sonu][j+1]+(g[u][j+1]−g[sonu][j])}dp[u][j]=min\{dp[son_u][j+1]+(g[u][j+1]-g[son_u][j])\}dp[u][j]=min{dp[sonu][j+1]+(g[u][j+1]g[sonu][j])}
    为啥要减掉g[sonu][j]g[son_u][j]g[sonu][j]因为贡献重复计算了

  8. 那么ggg数组怎么算呢?很好算的g[u][i]+=g[sonu][i−1]g[u][i]+=g[son_u][i-1]g[u][i]+=g[sonu][i1]

  9. 注意点1:就是dp[u][0]=0+g[u][1]dp[u][0]=0+g[u][1]dp[u][0]=0+g[u][1]这是不合法的因为实际上并没有包含到uuu节点,那么dp[u][0]dp[u][0]dp[u][0]只能算第二种情况就是子树传递贡献上去!!

  10. 注意点2:就是实际上dp[u][i+1]dp[u][i+1]dp[u][i+1]是对dp[u][i]dp[u][i]dp[u][i]有贡献影响的,因为覆盖范围≥i+1\ge i+1i+1肯定也≥i\ge ii,ggg数组同理也是g[u][i−1]g[u][i-1]g[u][i1]g[u][i]g[u][i]g[u][i]是用贡献的因为距离≤i−1\leq i-1i1肯定也≤i\leq ii

  11. 注意点3g[u][0]=dp[u][0]g[u][0]=dp[u][0]g[u][0]=dp[u][0]


AC code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 5010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {read(first);read(args...);
}
int n, lim = 5000;
vector<int> G[maxn];
int dp[maxn][maxn]; // dp[u][j] 表示覆盖完u这个子树并且覆盖了上面所有距离<=j的祖先节点最小费用
int g[maxn][maxn]; // g[u][i] 表示覆盖了距离u >= i的所有节点所需要的最小费用
void dfs(int u, int fa) {int min_son = -1;for(auto it : G[u]) {if(it == fa) continue;dfs(it,u);for(int i = 1; i <= lim; ++ i) g[u][i] += g[it][i-1];if(min_son == -1 || dp[it][1] < dp[min_son][1])min_son = it;}if(G[u].size() == 1 && u != 1) dp[u][0] = 1; // 叶子节点为1else dp[u][0] = dp[min_son][1] + g[u][1] - g[min_son][0];dp[u][lim] = INF;// 把边界设置成无穷大for(int i = lim - 1; i >= 1; -- i) {dp[u][i] = g[u][i+1] + i;for(auto it : G[u]) if(it != fa) {dp[u][i] = min(dp[it][i+1]-g[it][i]+g[u][i+1],dp[u][i]);}} // 处理一下同层之间的贡献for(int i = lim-1; i >= 0; -- i) dp[u][i] = min(dp[u][i],dp[u][i+1]); g[u][0] = dp[u][0]; // g的边界for(int i = 1; i <= lim; ++ i) g[u][i] = min(g[u][i],g[u][i-1]);
}int main() {IOS;cin >> n;for(int i = 1; i < n; ++ i) {int u, v;cin >> u >> v;G[u].push_back(v);G[v].push_back(u);}   dfs(1,0);cout << g[1][0];return 0;
}

http://lihuaxi.xjx100.cn/news/285947.html

相关文章

UI整理-----part2--UI控件

1.label &#xff08;1&#xff09;label的默认行数是1&#xff0c;可以通过label.numberOfLines 0 实现自动换行 &#xff08;2&#xff09;通过 [label sizeToFit] 可以让label根据text适当设置高度和宽度 2.button &#xff08;1&#xff09;可以通过 UIButton *but [UIBu…

一键fxxk,代码修复神器拯救你

作者 | 一一出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;在成为一个合格的开发者之前&#xff0c;大多数人一般都经历过被命令行反复“fuck”蹂躏。当然&#xff0c;改代码改不动了&#xff0c;你的内心也是“无 fuck 可说”&#xff0c;尤其在检查半天之后发现这…

只需 9.9 元!前 Facebook 工程师 7 天带你掌握 7 大数据结构,大厂面试必备!

数据结构与算法是互联网大厂面试的敲门砖&#xff0c;也是开发者精益求精、持续提升的内功基础。工作中选择合适的数据结构&#xff0c;往往能达到事半功倍的效果。然而真正学习算法的时候&#xff0c;又是另外一番景象&#xff0c;因为真正基础、真正核心的东西肯定是学习的难…

第1关:实现一个顺序存储的队列

#if !defined(SEQUENCE_QUEUE_H_LIELJE7398CNHD_INCLUDE_) #define SEQUENCE_QUEUE_H_LIELJE7398CNHD_INCLUDE_ / typedef int T; struct SeqQueue { T* data; // 指向数据元素数组的指针int front; // 下一个出队元素的数组下标int rear; // 下一个入队元素应该存放的单元的数…

小雨坐地铁--[最短路分层建图+虚点]

也是第一次接触这种分层建图的最短路 思路&#xff1a;由题目我们可以知道某些站点是可以连接好几条地铁线路的&#xff0c;那么对于每条地铁线路我们可以把他当成一幅图来算。当然图是个无向图&#xff0c;所以要加两次边。 add(i*nx,i*npre,b); //乘i的话就是说把他建在第i…

Google经典面试题解析

作者 | Alex Golec译者 | 弯月责编 | 屠敏出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;在深入问题之前&#xff0c;有一个令人振奋的消息&#xff1a;我离开了Google&#xff01;我激动地宣布&#xff0c;我已经加入了Reddit&#xff0c;并在纽约市担任项目经理…

树形dp ---- gym101655 D - Delta Quadrant 树上连通块思维换根 + 树形dp

题目链接 题目大意&#xff1a; 给你一颗NNN个节点的树&#xff0c;树上每条边有边权就是遍历的时间&#xff0c;你可以从任意节点出发遍历N−kN-kN−k个点并且回到出发点&#xff0c;问你最短的时间是多少&#xff1f; k∈[0,min(N,20)],N∈[1,1e4]k\in[0,min(N,20)],N\in[1,…

任正非:要感谢特朗普,他一吓唬,治好了华为人的富裕病,都努力工作了

华为“心声社区”前几日公布了任正非接受北欧媒体采访的纪要。据纪要显示&#xff0c;前几日任正非接受采访&#xff0c;参与采访的记者来自瑞典国家电视台、丹麦广播公司等多家媒体。任正非在采访中就华为建筑的欧式设计、美国总统特朗普、5G和人工智能等问题作答。任正非(图源…