NCPC 2012 Juice(练习)

第二次暑假集训的第一场练习赛的最后一题。。。悲剧了,看完题目,感觉是树形DP,于是不打算写,好久没搞了,不过我感觉最大流也可以过,于是模板上去了,一直WA。理所当然的。好吧,感言到此为止。

题意:

N 个点, 编号 0 ~ N, 有 N 条边,将 所有点(N + 1 个点)连起来,保证每一个点只有一个前驱(父节点),显然这个是个树状图,无环。

每一条边容量为 c, 表示每一个点点亮的能量所需为 r, 0 为源点(根节点),可输出能量为无限大。

问题:

求最多能点亮几个点。

解题思路:

整体:树形DP。

每个节点上:分组背包。

背包组:自身节点与子节点。

每组背包的物品:0 ~ c 的各种状态。

PS:

根节点不是背包,只要把它的所有子节点的最优值累加即可。

数组:1000 * 100,二维。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn = 1100;
int max( int a, int b ){ return a > b ? a : b; }
struct Edge{
    int v, c, next;
}edge[maxn];
int tot, head[maxn];
int mat[maxn], dp[maxn][110], n, ans;
void init()
{
    tot = 0;
    memset( head, -1, sizeof(head) );
    ans = 0;
}
void add_edge( int u, int v, int c )
{
    edge[tot].v = v;
    edge[tot].c = c;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void dfs( int u, int c )
{
    int i, j, k, v;
    if( u != 0 )
    for( i = mat[u]; i <= c; i++ )
        dp[u][i] = 1;
    for( i = head[u]; i != -1; i = edge[i].next )
    {
        v = edge[i].v;
        dfs( v, edge[i].c );
        if( u == 0 )
        {
            ans += dp[v][edge[i].c];
            continue;
        }
        for( j = c; j >= 0; j-- )
            for( k = 0; k <= edge[i].c; k++ )
                if( j >= k )
                    dp[u][j] = max( dp[u][j], dp[u][j - k] + dp[v][k] );
    }
}
int main()
{
    int i, p, c;
    while( ~scanf( "%d", &n ) )
    {
        init();
        for( i = 1; i <= n; i++ )
        {
            scanf( "%d%d%d", &p, &mat[i], &c );
            add_edge( p, i, c );
        }
        memset( dp, 0, sizeof(dp) );
        dfs( 0, 100000 );
        printf( "%d\n", ans );
    }
    return 0;
}
 
 
 
 
 
/**************************************************************
    Problem: 4119
    User: 2011339930128
    Language: C++
    Result: Accepted
    Time:88 ms
    Memory:5788 kb
****************************************************************/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值