树形DP-HDU1520

来源:互联网 发布:ubuntu wine安装 编辑:程序博客网 时间:2024/04/29 18:53

什么是树形DP呢?看完这个入门题目,估计你就明白了!

例题

HDU1520-Anniversary party
题目描述:人们都不愿意在聚会中遇到自己的直接上司。现在给出每个人能带给聚会的欢乐值以及他们直接的上司下属关系,问聚会欢乐值最高可以是多少?
输入输出:参见评测网站题目。

解析

对于这道题,我们可以先使用邻接表存储某人和他的直接下属。因为我们知道:如果某人去参加聚会,那么他的直接下属就一定不能参加;如果某人不去参加聚会,那么他的直接下属可以选择参加或不参加。
所以对于dp数组和状态转移方程有:
dp[i][0]表示编号为i的人不去聚会;
dp[i][1]表示编号为i的人去聚会。
dp[i][0]+=max{dp[i的直接下属][0],dp[i的直接下属][1]};
dp[i][1]+=dp[i的直接下属][0];
dp[i][1]还要加上v[i],也就是他的欢乐值,别忘了他自己!

#include<cstdio>#include<cstring>#define N 6005struct node{    int from,to,next;}edge[2*N];int head[N],tol,visit[N],val[N],degree[N],dp[N][3];void add(int a,int b)//邻接表存储 {    tol++;    edge[tol].from=a;     edge[tol].to=b;     edge[tol].next=head[a];     head[a]=tol;}int max(int a,int b){    return a>b?a:b;}void dfs(int root){    int j,u,ans1,ans0;    visit[root]=1;    ans1=ans0=0;    for(j=head[root];j!=-1;j=edge[j].next)//对于某人的所有直接下属进行讨论     {        u=edge[j].to;        if(!visit[u])dfs(u);        ans0+=max(dp[u][0],dp[u][1]);//对于某人不去,直接下属可选择去或不去         ans1+=dp[u][0];//对于某人去,直接下属只能不去     }    dp[root][1]=ans1+val[root];    dp[root][0]=ans0;}int main(){    int i,n,sum,a,b;    while(scanf("%d",&n)!=EOF)    {        for(i=1;i<=n;i++)            scanf("%d",&val[i]);        memset(head,-1,sizeof(head));        memset(degree,0,sizeof(degree));        tol=0;        while(scanf("%d%d",&a,&b)!=EOF)        {            if(a==0 && b==0) break;            add(b,a);            degree[a]++;        }        memset(visit,0,sizeof(visit));        memset(dp,0,sizeof(dp));        sum=0;        for(i=1;i<=n;i++)        {            if(degree[i]==0)//如果某人再没有直接上司(说明他是根节点)。            //注意:可能有多个根节点!!!             {                dfs(i);                sum+=max(dp[i][0],dp[i][1]);            }        }        printf("%d\n",sum);    }    return 0;}
1 0
原创粉丝点击