【树形DP】HDU 4044 GeoDefense

通道:http://http//acm.hdu.edu.cn/showproblem.php?pid=4044

题意:一棵树(编号1-n),1是敌人出口(只有一个敌人)。叶子节点是我军。在节点处装大炮。每个节点有 k 种大炮选择,可是每个节点最多装一个大炮。每个大炮有一个花费和一个威力值。你一共有m钱,怎么能使威力值最大。敌人去攻击哪个我军是任意的,所以最大威力是每条路值和的最小值。大炮放在叶子节点也是管用的

思路:dp[i][j]表示i结点用j费用打掉的最大hp,dp[i][j]=max(t,min(dp[son][j-k],dp[v][k])),对于每个根节点,决策是选一条最大的儿子来更新即可。

代码:

 

#include<cstdio>  
#include <cstring>
#include <algorithm>

using namespace std;

const int me=2222;  
const int mn=1111;  
const int mm=222;  
int t[me],p[me];  
int h[mn],f[mn][mm],s[mn],c[mn][55],w[mn][55],cur[mm];  
bool vis[mn];  
int i,j,k,n,m,T,e;  
void DP(int u)  {  
    int i,j,k,v;  
    bool flag=0;  
    vis[u]=1;  
    for(i=h[u]; i; i=p[i])  
        if(!vis[v=t[i]]) {  
            DP(v);  
            if(flag) {  
                for(j=0; j<=m; ++j)cur[j]=0;  
                for(j=m; j>=0; --j)  
                    for(k=0; k<=j; ++k)  
                        cur[j]=max(cur[j],min(f[u][j-k],f[v][k]));  
                for(j=0; j<=m; ++j)f[u][j]=cur[j];  
            } else for(flag=1,j=0; j<=m; ++j)f[u][j]=f[v][j];  
        }
    for(i=0;i<=m;++i)cur[i]=f[u][i];  
    for(i=0;i<s[u];++i)  
        for(j=m;j>= c[u][i];--j)  
            cur[j]=max(cur[j],f[u][j-c[u][i]]+w[u][i]);  
    for(i=0;i<=m;++i)f[u][i]=cur[i];  
}  
int main() {  
    scanf("%d",&T);  
    while(T--) {  
        scanf("%d",&n);  
        for(i=0; i<=n; ++i)h[i]=vis[i]=0;  
        for(k=e=1; k<n; ++k) {  
            scanf("%d%d",&i,&j);  
            t[e]=j,p[e]=h[i],h[i]=e++;  
            t[e]=i,p[e]=h[j],h[j]=e++;  
        }  
        scanf("%d",&m);  
        memset(f, 0, sizeof f);
        for(i=1; i<=n; ++i)  
            for(scanf("%d",&s[i]),j=0; j<s[i]; ++j)  
                scanf("%d%d",&c[i][j],&w[i][j]);  
        DP(1);  
        printf("%d\n",f[1][m]);  
    }  
    return 0;  
}  
View Code

 

posted @ 2014-11-03 19:46  mithrilhan  阅读(161)  评论(0编辑  收藏  举报