现在的位置: 首页 > 综合 > 正文

hdu 1011 Starship Troopers 树形dp

2017年07月12日 ⁄ 综合 ⁄ 共 1345字 ⁄ 字号 评论关闭

题意:

有一颗以1为根结点的树,每个结点有ai的敌对兵力,以及bi价值的物品,一开始有m个自方兵力,每个己方兵力可以战胜20个敌对兵力。入口在1结点,只有战胜一个结点,才能获得这个结点的物品,以及进入这个结点的子结点。为了节约时间,每个结点都要留下对抗的兵力,其余继续前进,问最多可以获得多大价值的物品。

题解:

典型的树形dp。dp[i][j]表示i结点剩余j兵力的情况下最多能获得多大价值的物品。dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[u][k]);其中u为i的孩子。由于一个结点可能有多个子结点,就变成了01背包的问题。

注意:一个结点的敌对兵力为0时,不需要再这个结点驻守兵力,但必须有己方兵力经过才能获得物品。

特殊样例:

5 2
0 1
0 1
0 5
0 1
0 2
1 2
1 3
2 4
2 5

答案是9。一个兵从1到达3,获得价值5;一个兵从1到达5,获得价值3;再加上根结点1的价值1。

代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cctype>
using namespace std;

const int maxn=1e2+10;
struct node{
    int foe,w;
}f[maxn];
int dp[maxn][maxn];
vector<int>e[maxn];
void dfs(int i,int pre,int m)
{
    int j,k,p,q,u;
    for(j=f[i].foe;j<=m;j++)dp[i][j]=f[i].w;
    for(j=0;j<e[i].size();j++)
    {
        u=e[i][j];
        if(u!=pre)
        {
            dfs(u,i,m);
            for(p=m;p>=f[i].foe;p--)
            {
                for(q=0;q+f[i].foe<=p;q++)
                    dp[i][p]=max(dp[i][p],dp[i][p-q]+dp[u][q]);
            }
        }
    }
    dp[i][0]=0;//没有驻留兵力的时候,即使该点的敌对兵力为0也无法获得物品。
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==-1&&m==-1)break;
        int i,j,k,a,b;
        for(i=0;i<n;i++)
        {
            e[i].clear();
            scanf("%d%d",&a,&f[i].w);
            f[i].foe=a==0?0:(a-1)/20+1;
        }
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            a--;b--;
            e[a].push_back(b);
            e[b].push_back(a);
        }
        //for(i=0;i<n;i++)for(j=0;j<e[i].size();j++)printf("*%d %d\n",i,e[i][j]);
        memset(dp,0,sizeof(dp));
        dfs(0,-1,m);
        printf("%d\n",dp[0][m]);
    }
    return 0;
}

抱歉!评论已关闭.