[树形DP] HDU 4340
来源:互联网 发布:淘宝网开直通车的要求 编辑:程序博客网 时间:2024/05/22 00:25
Capturing a country
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1321 Accepted Submission(s): 542
For simplicity, we assume that there is only one path to go from one city to another city.
31 2 53 8 11 21 3
3
题意:
有一棵树,两个人 a 和 b 要去占领这棵树上的所有点,两个人占领每个点所需的花费各不相同
如果 a 占领了 i 点,那么去占领 与 i 相邻的点的时候,该点的花费减半,b 也是如此
问占领完整棵树所需最小花费
思路:
把这棵树分成几棵小的子树,每个子树只让同一个人占领
但是怎么操作呢? 用树形DP
建好树之后,从根节点往下深搜,搜到叶子节点之后开始回溯记录值
sa:表示该点取 a 的时候,且未确定起点,下面的子树的最小花费
sb:表示该点取 b 的时候,且未确定起点,下面的子树的最小花费
da:表示该点取 a 的时候,让取值最小的起点额外花费(即子树中 a 起点值的一半)
db:表示该点取 a 的时候,让取值最小的起点额外花费(即子树钟 b 起点值的一半)
dp[i][0][0]:表示 i 点取 a 且 尚未确定起点的最小花费
dp[i][0][1]:表示 i 点取 a 且 已经确定起点的最小花费
dp[i][1][0]:表示 i 点取 b 且 尚未确定起点的最小花费
dp[i][1][1]:表示 i 点取 b 且 已经确定起点的最小花费
那么:到达根节点之后dp[i][0][0] = sa + a[i] / 2 ; 都是取一半价值
dp[i][0][1] = min(sa + a[i] , sa + a[i] / 2 + da) 该点为起点或者下面的某个点为起点
b的情况也是同上
每个点回溯后更新 sa sb
sa += min(dp[v][0][0],dp[v][1][1]) 如果该点取 a ,那么就加等于下面a未确定起点的
或者是 下面 b 已经确定起点的 ,取小的那个值
更新 da db
da = min(da,dp[v][0][1] - min(dp[v][0][0],dp[v][1][1]))
取当前点为a,且已确定起点的值,减去下面的子树为 a 为确定 或为 b已确定的 两个值中小的那个(因为小的那个才是构成当前 取a 且已确定的最优情况下的子树值)
#include <cstdio>#include <algorithm>#include <cstring>#include <vector>#include <cmath>using namespace std;#define ll long long#define mem(a,x) memset(a,x,sizeof(a))#define maxn 105const int inf = 1 << 30;int n,a[maxn],b[maxn],dp[maxn][2][2];vector<int>vec[maxn];// dp[i][0][0]:表示 i 点取 a 且 尚未确定起点的最小花费// dp[i][0][1]:表示 i 点取 a 且 已经确定起点的最小花费// dp[i][1][0]:表示 i 点取 b 且 尚未确定起点的最小花费// dp[i][1][1]:表示 i 点取 b 且 已经确定起点的最小花费 void tree_dp(int x,int pre){int sz = vec[x].size();int sa,sb,da,db;sa = sb = 0;da = db = inf;for(int i = 0;i < sz;i++){int v = vec[x][i];if(v == pre)continue;tree_dp(v,x);sa += min(dp[v][0][0],dp[v][1][1]);// 表示该点取 a 的时候,且未确定起点,下面的子树的最小花费sb += min(dp[v][1][0],dp[v][0][1]);da = min(da,dp[v][0][1] - min(dp[v][0][0],dp[v][1][1]));//更新预计起点的额外值db = min(db,dp[v][1][1] - min(dp[v][1][0],dp[v][0][1]));}dp[x][0][0] = sa + a[x] / 2;// 该点取半值,未确定起点,全部取半值dp[x][0][1] = min(sa + a[x],sa + a[x] / 2 + da); // 该点做起点 或者 该点取半值,起点取下面的别的点dp[x][1][0] = sb + b[x] / 2;dp[x][1][1] = min(sb + b[x],sb + b[x] / 2 + db);}void init(){for(int i = 0;i <= n;i++){vec[i].clear();}mem(dp,0);}int main(){int u,v;while(scanf("%d",&n) != EOF){init();for(int i = 1;i <= n;i++){scanf("%d",&a[i]);}for(int i = 1;i <= n;i++){scanf("%d",&b[i]);}for(int i = 1;i < n;i++){scanf("%d %d",&u,&v);vec[u].push_back(v);vec[v].push_back(u);}tree_dp(1,0);int ans = min(dp[1][0][1],dp[1][1][1]);printf("%d\n",ans);}return 0;}
- hdu 4340 树形dp
- hdu 4340 树形DP
- HDU 4340 树形DP
- [树形DP] HDU 4340
- hdu - 4340 - Capturing a country - 树形dp
- hdu 4340 树形dp+染色问题
- HDU 4340 Capturing a country 树形DP
- HDU 4340 Capturing a country(树形DP)
- 树形dp hdu Computer
- 【树形DP】hdu 1520
- hdu 1054 #树形DP
- hdu 4303 树形dp
- hdu 4267 树形dp
- hdu 4383 树形dp
- HDU 2196 树形dp
- HDU 2196 树形dp
- hdu 1054 树形dp
- HDU 4276 树形DP
- Rhyme/ Linux fdisk 手工分区
- Golang设计模式之代理模式
- 2017.10自考总结
- SSO单点登录三种情况的实现方式详解
- Action如何去使用session request ,application等。。。
- [树形DP] HDU 4340
- c++ 继承
- NYOJ 21-三个水杯
- 用Scrapy和Selenium+PhantomJS爬淘宝评论
- Docker基本使用命令
- Javascript函数将文本拆分为相同长度的两个字符串
- 可以玩的游戏:三子棋
- 64位Centos7上汇编运行32位程序
- 在javascript中,如何处理FSharpOption对象