2011 Asia Beijing Regional Online Contest-1005 hdu4044 GeoDefense-tjuqxy

昨天一个下午边看视频边写的代码,今天又一个下午来调试,本来对这份代码很没信心的,觉得那些想法有问题,今天跟同学又讨论了一下午找代码里的Bug,把程序认认真真读了一遍之前写的那些想法都明白了:树形DP,分组背包空间优化,建树,DP状态转移过程中的“滚动数组”。 觉得对DP有了更深入的理解吧,代码发上来纪念下。

最后膜拜下政哥……



#include <iostream>
#include <memory.h>
#include <vector>
#include <cstdio>

using namespace std;

vector<int> edge[1005];
vector<int> price[1005];
vector<int> power[1005];
int n,m,par[1005],dp[1005][205];

void init()
{
    for(int i=0; i<=n; i++) edge[i].clear();
    for(int i=0; i<=n; i++) price[i].clear();
    for(int i=0; i<=n; i++) power[i].clear();
    memset(par,0,sizeof(par));
    memset(dp,0,sizeof(dp));
}

void dfs(int curr)
{
    int tmp,len = edge[curr].size();
    for(int i=0; i<len; i++)
    {
        if(edge[curr][i]!=par[curr])
        {
            par[edge[curr][i]] = curr;  // 标记父亲结点建树
            dfs(edge[curr][i]);
        }
    }
    tmp = 0;
    if(len>1)
    {
        if(edge[curr][tmp]==par[curr]) tmp=1;
        for(int i=0;i<=m;i++) dp[curr][i]=dp[edge[curr][tmp]][i];   //用孩子的第一个结点对当前结点孩子的分组背包进行初始化
    }
    for(int i=tmp+1; i<len; i++)
    {
        if(edge[curr][i]!=par[curr])
        {
            for(int v=m; v>=0; v--)
            {
                int ans = 0;    // 一定要另开个ans,我以前直接用的dp[curr][v]果断有问题
                for(int j=0; j<=v; j++)
                {
                    ans=max(ans,min(dp[curr][v-j],dp[edge[curr][i]][j]));
                }
                dp[curr][v] = ans;
            }
        }
    }
    for(int v=m; v>=0; v--)
    {
        int ans = dp[curr][v];  // 一定要用ans,而且ans不能赋值为0,因为当前结点可以没有塔
        for(int i=0; i<price[curr].size(); i++)
        {
            if(v>=price[curr][i])
            {
                ans = max(ans,dp[curr][v-price[curr][i]]+power[curr][i]);
            }
        }
        dp[curr][v] = ans;
    }
}

int main()
{
    int k,a,b,c,maxVal;
    while(scanf("%d",&k)!=EOF)
    {
        while(k--)
        {
            init();
            scanf("%d",&n);
            for(int i=1; i<n; i++)
            {
                scanf("%d%d",&a,&b);
                edge[a].push_back(b);
                edge[b].push_back(a);  // 双向建边
            }
            edge[1].push_back(0);
            scanf("%d",&m);
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&c);
                while(c--)
                {
                    scanf("%d%d",&a,&b);
                    price[i].push_back(a);
                    power[i].push_back(b);
                }
            }
            dfs(1);
            maxVal = 0;
            for(int i=0; i<=m; i++)
            {
                if(dp[1][i]>maxVal) maxVal=dp[1][i];
            }
            printf("%d\n",maxVal);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值