没有上司的舞会 树形DP 经典题目

来源:互联网 发布:苹果大麦网抢票软件 编辑:程序博客网 时间:2024/05/21 20:25

题目描述:

Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。

输入:

第一行一个整数N。(1< =N< =6000) 接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128< =Ri< =127) 接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。 最后一行输入0,0。

输出:

输出最大的快乐指数。

样例输入:

711111111 32 36 47 44 53 50 0

样例输出:

5

简析:

  开门见山,这题用DP做,状态为dp[x][0]和dp[x][1],dp[x][0]表示x不来时,他及其子树的最大快乐指数,dp[x][1]则表示x要来时,他及其子树的最大快乐指数。
显然,我们需要先确定位于叶节点的状态再来确定父节点的状态,因此DP过程建立在dfs的基础上。
状态转移方程:(v为x的子节点)
dp[x][1]+=dp[v][0] x与v不能同时到场
dp[x][0]+=max(dp[v][1],dp[v][0]) x不在,v可到可不到。
由于是求总的快乐指数,所以用加法。

代码:

#include<stdio.h>int max(int x,int y){    return x>=y?x:y;}int scan(){    int x=0,f=1;    char c=getchar();    while(c>'9'||c<'0'){        if(c=='-')            f=-1;        c=getchar();    }    while(c>='0'&&c<='9')        x=(x<<1)+(x<<3)+c-'0',        c=getchar();    return x*f;    //读入优化}struct node{    int to,next;};node edge[7000];int edge_num,n,fa[7000],root,pre[7000],dp[7000][2];void add(int x,int y){    edge[++edge_num].next=pre[x];    edge[edge_num].to=y;    pre[x]=edge_num;}void tree_dp(int x){     //中心函数    for(int i=pre[x];i;i=edge[i].next){        int v=edge[i].to;        if(v!=fa[x]){            tree_dp(v);            dp[x][1]+=dp[v][0];            dp[x][0]+=max(dp[v][1],dp[v][0]);        }    }}int main(){    int i,x,y;    n=scan();    for(i=1;i<=n;i++)        dp[i][1]=scan();   //直接输入    for(i=1;i<=n-1;i++){        x=scan(),y=scan();        add(y,x);        fa[x]=y;    }    x=scan(),y=scan();    root=1;    while(fa[root])        root=fa[root];    tree_dp(root);    printf("%d",max(dp[root][1],dp[root][0]));}