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

hdu 1561 The more, The Better 树形dp

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

题意:

有n座城堡,里边藏有价值val[i]的宝物,现在要去攻打这些城堡,总共能攻打m座城堡;有些城堡有前置条件,即需要攻击某个城堡a,必须已经攻占另个城堡b,求最大能获得价值。

题解:

树形dp。

一开始的图不是一颗树,我们需要将之变成一棵树,设虚拟城堡0,所以没有前置条件的城堡都需要先攻打城堡0,才能攻打。那么就能画出一颗以0为根的树。之后就是树形dp了,dp[i][j]表示i结点,剩余兵力为j(还能攻打j个城堡)的时候,能获得的最大宝物。dp[i][j]=max(dp[i][j],do[i][j-k]+dp[u][k]),其中u为i的子结点。那么对于所有的i的子结点,要使得dp[i][j]最大,就能转换成01背包问题了。

注意:由于增加了一个虚拟结点0,所以能攻打的城堡数m需要+1,即用于攻打城堡0,获得的价值val[0]=0。

代码:

#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=202;
int dp[maxn][maxn],val[maxn];
vector<int>e[maxn];
int n;
void dfs(int i,int pre,int m)
{
    for(int j=1;j<=m;j++)dp[i][j]=val[i];
    for(int j=0;j<e[i].size();j++)
    {
        int u=e[i][j];
        if(u!=pre)
        {
            dfs(u,i,m);
            for(int k=m;k>=1;k--)
            {
                for(int p=0;p<k;p++)
                dp[i][k]=max(dp[i][k],dp[i][k-p]+dp[u][p]);
            }
        }
    }
}
int main()
{
    int m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        int i,j,k,a,b;
        for(i=0;i<=n;i++)e[i].clear();
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&a,&val[i]);
            e[a].push_back(i);
        }
        dfs(0,-1,m+1);
        printf("%d\n",dp[0][m+1]);
    }
    return 0;
}

抱歉!评论已关闭.