树状DP HDU1520 Anniversary party

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520

题意:职员之间有上下级关系,每个职员有自己的happy值,越高在派对上就越能炒热气氛。但是必须是他的上司不在场的情况。求派对happy值的和最大能是多少。

PS:这是多组输入,一开始还没看出来。。。

dp[i][0]代表第i个职员不来的情况下的快乐值,dp[i][1]是第i个职员来的情况下的快乐值

那很显然有

dp[上司][来] += dp[下属][不来];
dp[上司][不来] += Max(dp[下属][来],dp[下属][不来]);

树状DP其实和普通DP没啥大差,就是需要遍历来确定子节点,这个题做起来还是不难的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=1<<30;
const int maxn=6007;
const double pi=acos(-1);
const int mod=1e9+7;
int fa[maxn];
int root;
int dp[maxn][2];int n;
void dp_rule(int root){for(int i=1;i<=n;i++){
        if(fa[i]==root){
            //vis[i]=1;
            dp_rule(i);//注意这里一定要先遍历,之后再加在dp数组上 
            dp[root][0]+=max(dp[i][0],dp[i][1]);//上司不去,下属去或不去选大的一个 
            dp[root][1]+=dp[i][0];//上司去,下属只能不去 
        }
    }
}
int main(){
    while(~scanf("%d",&n)){
    memset(vis,0,sizeof(vis));
    memset(fa,0,sizeof(fa));
    memset(dp,0,sizeof(dp));    
    for(int i=1;i<=n;i++)scanf("%d",&dp[i][1]);//输入这里要注意啊 
    int l,k;
    while(~scanf("%d%d",&l,&k)){
        if(l==0&&k==0)break;
        fa[l]=k;        
    }
    for(int i=1;i<=n;i++){
        if(!fa[i]){
            root=i;
            break;
        }
    }
    dp_rule(root);
    int ans=max(dp[root][0],dp[root][1]);
    cout<<ans<<endl; } 
    return 0;
}
原文地址:https://www.cnblogs.com/qingjiuling/p/10541766.html