HDU 1011 Starship Troopers 树形DP(0-1背包)

题意:一棵树,有n个结点,每个结点有w[i]个bug,有p[i]的brain。我从1号结点开始走,带着m个战士。
1个战士可以消灭20个bugs如果我把某个结点的所有bug都消灭了我就能得到那个结点的brain。
如果想攻击当前结点,那么必须先攻击了它的父结点(1号点除外)。
注意:
1. 其中当你攻占了当前结点,你可以分派人手,走向几个不同的子结点,去攻占更多。也就是说,不是单一的路径。
2. 如果输入0个战士直接输出0,即使该洞bug数为0,要获得该洞brain值,也需要至少一人经过该洞穴(可以不停留),而用dfs计算会出现正值。
 
本题数据小,节点100,如果数据大了尽量不要用vector,可能会超时,建议自己写个邻接表。
 
树形DP,有一定的格式,下面是最常见的模板(一般题目都可以这么做):
void dfs(int u)
{
    int i, j, k;
    vis[u]=1;
    操作:u节点dp初始化
    for(i=0;i<edge[u].size();i++)
    {
        int v=edge[u][i];
        if(vis[v])continue;
        dfs(v);
        操作:子节点状态转移到父亲节点
    }
}



int main()
{
操作:输入
操作:建图
dfs(根节点);
printf("根节点的状态");
}

AC代码:

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
int n, m, w[101], p[101];
bool vis[101];
vector<int>edge[101];
int dp[101][101];
void dfs(int u)
{
    int i, j, k;
    vis[u]=1;
    //for(j=0;j<w[u];j++)//各节点初始化,如果能装,先把节点u的物品装进背包
    //    dp[u][j]=0;
    for(j=w[u];j<=m;j++)
        dp[u][j]=p[u];
    for(i=0;i<edge[u].size();i++)
    {
        int v=edge[u][i];
        if(vis[v])continue;
        dfs(v);
        for(j=m;j>=w[u];j--)
            for(k=1;k<=j&&j-k>=w[u];k++)
                dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
    }
}
int main()
{
    int i ,j, x, y;
    while(~scanf("%d%d",&n,&m))
    {
        if(m==-1&&n==-1)break;
        for(i=1;i<=n;i++)
            edge[i].clear();
        for(i=1;i<=n;i++)
            scanf("%d%d",&w[i],&p[i]),w[i]=(w[i]+19)/20;
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            edge[x].push_back(y);
            edge[y].push_back(x);
        }
        memset(dp,0,sizeof(dp));
        memset(vis,0,sizeof(vis));
        //即使该洞bug数为0,要获得该洞brain值,也需要至少一人经过该洞穴(可以不停留)。
        if(!m){printf("0\n");continue;}//必须要考虑0这个特殊数据。
        dfs(1);
        printf("%d\n",dp[1][m]);
    }
    return 0; 
}

 

posted @ 2012-08-14 15:06  To be an ACMan  Views(203)  Comments(0)    收藏  举报