bzoj1722: [Usaco2006 Mar] Milk Team Select 产奶比赛 树形dp

题目链接

bzoj1722: [Usaco2006 Mar] Milk Team Select 产奶比赛

题解

dp[i][j][0 / 1]
以i为根的子数中
相邻点对选了j个的最大价值

代码

#include<vector> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#define gc getchar() 
#define pc putchar 
inline int read() {
    int x = 0,f = 1; 
    char c = gc;  
    while(c < '0' || c > '9') {if(c == '-') f = - 1; c = gc;}  
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc; 
    return x * f; 
} 
#define LL long long 
void print(int x) { 
    if(x >= 10) print(x / 10); 
    pc(x % 10 + '0'); 
} 
const int maxn = 501; 
const int maxm = 100007; 
struct node { 
    int v,next; 
} edge[maxn << 1]; 
int num = 0,head[maxn]; 
inline void add_edge(int u,int v) { 
    edge[++ num].v = v; edge[num].next = head[u];head[u] = num; 
} 
int val[maxn]; 
int n,x; 
int f[maxn][maxn][2]; 
int siz[maxn]; 
void dfs(int x) { 
    siz[x] = 1; 
    f[x][0][0] = f[x][0][1] = 0; 
    for(int i = head[x];i;i = edge[i].next) { 
        int v = edge[i].v; 
        dfs(v); 
        siz[x] += siz[v]; 
        for(int j = siz[x];j >= 0;-- j) 
            for(int k = 0;k <= std::min(j,siz[v]); ++ k) {
                f[x][j][0] = std::max(f[x][j][0], f[x][j - k][0] + std::max(f[v][k][0],f[v][k][1])); 
                if(k) f[x][j][1] = std::max(f[x][j][1], f[x][j - k][1] + f[v][k - 1][1]);  
                f[x][j][1] = std::max(f[x][j][1], f[x][j - k][1] + f[v][k][0]);  
            } 
    } 
    for(int i = siz[x];i >= 0;-- i) f[x][i][1] += val[x]; 
} 
int main() { 
    n = read(); x = read(); 
    memset(f,-0x3f,sizeof f); 
    for(int i = 1;i <= n;++ i) { 
        val[i] = read(); 
        add_edge(read(),i); 
    } 
    dfs(0); 
    for(int i = n;i >= 0;-- i) { 
        if(f[0][i][0] >= x) { 
            print(i); return 0; 
        } 
    } 
    pc('-'),pc('1'); 
    return 0; 
} 

转载于:https://www.cnblogs.com/sssy/p/9763026.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值