首页 > 代码库 > HDU 4340
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 }
HDU 4340