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
",min(dp[1][0][1],dp[1][1][1]));
72     }
73     return 0;
74 }
View Code
原文地址:https://www.cnblogs.com/jie-dcai/p/4151532.html