ZOJ 3805 (树形DP)

题目链接http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5337

题目大意:方块连接,呈树形。每个方块有两种接法,一种接在父块边上,宽度+1,一种接在父块上面,宽度+0。且一个母块最多有2个子块。问全局的宽度最小是多少。

解题思路

对于一个方块,就两种接法。

设dp[i][0]=0,表示接在父块上面。

dp[i][1]=1,表示接在父块边上。

对于一个父块,如果没有子块,宽度不变。

如果有一个子块,肯定接在上面,加上子块的宽度。

如果有两个子块,则有两种解法,max(左1上2),max(左2上1), 注意这里两个子块不是加起来,因为只要把管子伸长,让两个子块相互重叠掉一部分宽度,所以取max

那么接这两个子块就得加上这两种解法的较小值。(min)

最后结果是dp[1][1],和dp[1][0]没关系,因为1块肯定要占一个宽度。

 

#include "cstdio"
#include "iostream"
#include "cstring"
using namespace std;
#define maxn 10005
struct Edge
{
    int next,to;
}e[maxn];
int dp[maxn][2],head[maxn],tol;
void addedge(int u,int v)
{
    e[tol].to=v;
    e[tol].next=head[u];
    head[u]=tol++;
}
void dfs(int root)
{
    int cnt=0,l1=0,l2=0,r1=0,r2=0;
    dp[root][0]=0,dp[root][1]=1;
    for(int a=head[root];a!=-1;a=e[a].next) dfs(e[a].to);
    for(int a=head[root];a!=-1;a=e[a].next)
    {
        int t=e[a].to;
        if(!cnt) {l1=dp[t][0],l2=dp[t][1];}
        else {r1=dp[t][0],r2=dp[t][1];}
        cnt++;
    }
    if(!cnt) return;
    else if(cnt==1) {dp[root][0]+=l1;dp[root][1]+=l1;}
    else
    {
        int a=max(l1,r2),b=max(l2,r1);
        dp[root][0]+=min(a,b);dp[root][1]+=min(a,b);
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int n,u;
    while(scanf("%d",&n)!=EOF)
    {
        memset(head,-1,sizeof(head));
        tol=0;
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&u);
            addedge(u,i);
        }
        dfs(1);
        printf("%d\n",dp[1][1]);
    }
}

 

3808409 2014-10-20 17:37:23 Accepted 3805 C++ 800 468 Physcal
posted @ 2014-10-20 17:53  Physcal  阅读(304)  评论(0编辑  收藏  举报