HDU 4340

好题一道啦。做这题时,抓住两个问题:一、给某点染色时,其连通的点是否已有一点以全部代价染色。二、该点染什么颜色。

嗯。第二个问题很容易,但第一个问题不容易了。我一开始就考虑祖父子三层结点的关系,认为在父结点时,要么子结点已染色,要么父结点已染色%#……*&¥%#……

很复杂。。。。

这是条件定得过于严格了,所以走不通。看了题解后,发现,可以把状态条件设得宽一点。

设dp[rt][0][0]为以rt为根的子树内,rt染0颜色,与其连通的块(同色,在子树内的)中,没有一个节点是以全部代价染色的,即没有入口点。

dp[rt][0][1]则为以rt为根的子树内,rt染0颜色,与其连通的块(同色,在子树内的)中,存在一个节点是以全部代价染色的。感觉这个存在实现设得妙,只要存在就可以,条件放宽了许多。

对于dp[r][1][0],dp[r][1][1]有同样的定义。

于是dp[rt][0][0]=sum(min(dp[son][0][0],dp[son][1][1]))+costrt/2;

dp[rt][0][1]=sum(min(dp[son][0][0],dp[son][1][1]))+min(costrt,costrt/2+min(dp[son][0][1]-min(dp[son][0][0],dp[son][1][1]))).解释一下min(dp[son][0][1]-min(dp[son][0][0],dp[son][1][1])。这是把子结点以根的子树状态转化为dp[rt][0][1]的最小代价,其中min(dp[son][0][0],dp[son][1][1])与方程开始的min(dp[son][0][0],dp[son][1][1])是一致的,因而又是一个巧妙的地方。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cmath>
 6 #define N 110
 7
 8 using namespace std;
 9 int costA[N],costB[N];
10
11 int dp[N][2][2];
12
13 struct edge{
14     int u,v;
15     int next;
16 }Edge[N*2];
17 int n,tot;
18 int head[N];
19
20 void addedge(int u,int v){
21     Edge[tot].u=u;
22     Edge[tot].v=v;
23     Edge[tot].next=head[u];
24     head[u]=tot++;
25 }
26
27 void dfs(int now,int pre){
28     bool leaf=true;
29     int sum0=0,sum1=0;
30     int CA=(1<<30),CB=(1<<30);
31     for(int e=head[now];e!=-1;e=Edge[e].next){
32         int v=Edge[e].v;
33         if(v!=pre){
34             leaf=false;
35             dfs(v,now);
36             sum0+=min(dp[v][0][0],dp[v][1][1]);
37             sum1+=min(dp[v][1][0],dp[v][0][1]);
38             CA=min(CA,dp[v][0][1]-min(dp[v][0][0],dp[v][1][1])+costA[now]/2);
39             CB=min(CB,dp[v][1][1]-min(dp[v][1][0],dp[v][0][1])+costB[now]/2);
40         }
41     }
42     if(leaf){
43         dp[now][0][0]=costA[now]/2;
44         dp[now][0][1]=costA[now];
45         dp[now][1][0]=costB[now]/2;
46         dp[now][1][1]=costB[now];
47     }
48     else{
49         dp[now][0][0]=sum0+costA[now]/2;
50         dp[now][0][1]=sum0+min(costA[now],CA);
51         dp[now][1][0]=sum1+costB[now]/2;
52         dp[now][1][1]=sum1+min(costB[now],CB);
53     }
54 }
55
56 int main(){
57     int u,v;
58     while(scanf("%d",&n)!=EOF){
59         tot=0;
60         memset(head,-1,sizeof(head));
61         for(int i=1;i<=n;i++)
62         scanf("%d",&costA[i]);
63         for(int i=1;i<=n;i++)
64         scanf("%d",&costB[i]);
65         for(int i=1;i<n;i++){
66             scanf("%d%d",&u,&v);
67             addedge(u,v);
68             addedge(v,u);
69         }
70         dfs(1,0);
71         printf("%d\n",min(dp[1][0][1],dp[1][1][1]));
72     }
73     return 0;
74 }

时间: 2024-08-29 14:15:05

HDU 4340的相关文章

HDU 4340 树形DP

[题意]: 给你一张无向图,无向图上每个点代表一个城市,有两个值Va,Vb,分别代表a,b占领该城市所需要消耗的时间,而且a或b去占领它们已经占领的城市的相领城市所需的花费为标准的一般.问最少需要花费多少钱. [知识点]: 树形DP [题解]:dp[u][i][0]:代表以u为根的子树中没有一个点为颜色i绘画开始点所需的最小花费,即字数中画有i颜色的点的代价都为原来的一般dp[u][i][1]:代表以u为根的子树中有一个点为颜色i绘画开始点所需的最小花费u的子树中涂i色的点中有一个点为其本身的代

hdu4340 树形dp

http://acm.hdu.edu.cn/showproblem.php?pid=4340 Problem Description Ant and Bob two army want to capture a country. The country is consist of N cities. To capture the city i, it takes Ant A[i] minutes, and Bob needs B[i] minutes to capture city i. Due

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

hdu 1207 汉诺塔II (DP+递推)

汉诺塔II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4529    Accepted Submission(s): 2231 Problem Description 经典的汉诺塔问题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往

[hdu 2102]bfs+注意INF

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2102 感觉这个题非常水,结果一直WA,最后发现居然是0x3f3f3f3f不够大导致的--把INF改成INF+INF就过了. #include<bits/stdc++.h> using namespace std; bool vis[2][15][15]; char s[2][15][15]; const int INF=0x3f3f3f3f; const int fx[]={0,0,1,-1};

HDU 3555 Bomb (数位DP)

数位dp,主要用来解决统计满足某类特殊关系或有某些特点的区间内的数的个数,它是按位来进行计数统计的,可以保存子状态,速度较快.数位dp做多了后,套路基本上都差不多,关键把要保存的状态给抽象出来,保存下来. 简介: 顾名思义,所谓的数位DP就是按照数字的个,十,百,千--位数进行的DP.数位DP的题目有着非常明显的性质: 询问[l,r]的区间内,有多少的数字满足某个性质 做法根据前缀和的思想,求出[0,l-1]和[0,r]中满足性质的数的个数,然后相减即可. 算法核心: 关于数位DP,貌似写法还是

HDU 5917 Instability ramsey定理

http://acm.hdu.edu.cn/showproblem.php?pid=5917 即世界上任意6个人中,总有3个人相互认识,或互相皆不认识. 所以子集 >= 6的一定是合法的. 然后总的子集数目是2^n,减去不合法的,暴力枚举即可. 选了1个肯定不合法,2个也是,3个的话C(n, 3)枚举判断,C(n, 4), C(n, 5) #include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false) using name

hdu 6166 Senior Pan

地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=6166 题目: Senior Pan Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 245    Accepted Submission(s): 71 Problem Description Senior Pan fails i