HDU-1011 Starship Troopers 树形dp

 题意是有一颗树,树上每个结点有虫子和宝藏,每个勇士能杀死20只虫子,杀死虫子才能获得宝藏。

很明显的树形dp dp[u][i]代表以u为根的子树花费i个勇士所获得的最大价值。

那么dp[u][i]=max(dp[u][i],dp[v][k]+dp[u][i-k]) (1<=k<=j)

状态转移方程并不难想,也并不难写,但是这题有一点恶心的是:即使某个结点没有虫子也要派个人过去收集金币。

解决办法是:状态转移的时候至少派一个个去,方程里即k>=1。不能转移子节点k=0的状态!!!!!

细节请看代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e2+10;
int n,m;
vector<int> G[N];
int dp[N][N],ct[N],vl[N];

int bugs(int x) { return (int)ceil((double)x/20); }

void dfs(int x,int fa,int m) {
    if (m<=0 || m<bugs(ct[x])) return;
    for (int i=bugs(ct[x]);i<=m;i++) dp[x][i]=vl[x];
    for (int i=0;i<G[x].size();i++) {
        int y=G[x][i];
        if (y==fa) continue;
        
        dfs(y,x,m-bugs(ct[x]));
        
        for (int j=m;j>=bugs(ct[x]);j--)
            for (int k=1;k<=j;k++)
                dp[x][j]=max(dp[x][j],dp[y][k]+dp[x][j-k]);
    }
}

int main()
{
    while (scanf("%d%d",&n,&m)==2 && n!=-1) {
        for (int i=1;i<=n;i++) scanf("%d%d",&ct[i],&vl[i]);
        for (int i=1;i<=n;i++) G[i].clear();
        for (int i=1;i<n;i++) {
            int x,y; scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        
        memset(dp,-0x3f,sizeof(dp));
        dfs(1,0,m);
        int ans=0;
        for (int i=1;i<=m;i++) ans=max(ans,dp[1][i]);
        cout<<ans<<endl;
    }
    return 0;
}

从HDU讨论区扒来的一个数据:

8 2
0 0
0 9
0 8
0 4
0 7
0 3
0 2
0 1
1 2
1 3
2 4
2 5
4 6
6 7
7 8

27

猜你喜欢

转载自www.cnblogs.com/clno1/p/10732648.html