【树形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; }