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 }