VOJ - Anniversary party (树形DP)

Anniversary party

题目链接:H - 树形DP例题 HDU - 1520

题意

在一个有根树上每个节点有一个权值,每相邻的父亲和孩子只能选择一个,问怎么选择总权值之和最大。


思路

树形dp的常规入门题:设dp[i][0]表示:当前这个点不选,dp[i][1]表示当前这个点选择的最优解。

转移方程:dp[cur][0]+=max(dp[son][1],dp[son][0]);//当前这个点不选,那他的孩子可选可不选,取
最大的。
dp[cur][1]+=dp[son][0]//当前这点选择,那他的孩子就不能选择。


代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back

typedef double db;
typedef long long ll;
const int MAXN = (int)6e3+7;
const int INF = (int)0x3f3f3f3f;

int N;
int dp[MAXN][2];
int rating[MAXN];
int fa[MAXN];
vector<int> G[MAXN];

int dfs(int root,int OK){
    int res = 0;
    if (dp[root][OK] != -1) return dp[root][OK];
    if (OK){
        rep(i,0,G[root].size()-1) {
            int v = G[root][i];
            res += dfs(v,0);
        }
    }
    else {
        rep(i,0,G[root].size()-1) {
            int v = G[root][i];
            res += max(dfs(v,0),dfs(v,1)+rating[v]);
        }
    }
    return dp[root][OK] = res;
}

int findfa(int x){
    if (x == fa[x]) return x;
    return fa[x] = findfa(fa[x]);
}

void init(){
    rep(i,0,N) G[i].clear();
    mmm(dp,-1);
    rep(i,1,N) fa[i] = i;
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    while (cin >> N){
        rep(i,1,N) cin >> rating[i];
        init();
        rep(i,1,INF){
            int x,y;
            cin >> x >> y;
            if (x==0&&y==0) break;
            G[y].pb(x);
            fa[x] = y;
        }
        rep(i,1,N-1){
            if (fa[i] == i) G[0].pb(i);
        }
        cout << dfs(0,0) << endl;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40513946/article/details/81277230