HDU4044 GeoDefense(树形dp+分组背包)
题意:
给定n个节点组成的树,1为敌方基地,叶子结点为我方结点。我们可以在每个结点安放炮台,至多一炮,然后就可以打炮,每个结点有ki种炮,每种炮有一个花费 和一个能量(能量对应着打掉敌人多少hp)。敌人可能往一个结点的每条分支跑,所以要想保证守住阵地,就要保证每个分支都要安放炮台。最后问怎么打炮,才 能使打掉的敌人hp最多。
思路:
树形dp,dp[i][j]表示以i为根节点消耗j能量所打掉的最大hp
这道题有个坑,就是建炮的花费有可能是0,这样需要处理一下,避免建多个炮。
先附上自己的代码(889ms):
/* *********************************************** Author :devil Created Time :2016/3/29 16:54:34 ************************************************ */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <stdlib.h> using namespace std; #define inf 0x7f7f7f7f #define N 1010 #define M 210 int n,m,dp[N][M]; vector<int>eg[N]; vector<int>price[N],power[N]; void init() { for(int i=0;i<N;i++) { eg[i].clear(); price[i].clear(); power[i].clear(); } } void dfs(int u,int fa) { if(eg[u].size()==1&&u!=1) { for(int i=0;i<=m;i++) dp[u][i]=0; for(int i=0;i<=m;i++) { for(int j=0;j<price[u].size();j++) { if(price[u][j]<=i) dp[u][i]=max(dp[u][i],power[u][j]); } } return ; } for(int i=0;i<=m;i++) dp[u][i]=inf; for(int i=0;i<eg[u].size();i++) { int to=eg[u][i]; if(to==fa) continue; dfs(to,u); for(int j=m;j>=0;j--) { int tmp=0; for(int k=0;k<=j;k++) tmp=max(tmp,min(dp[u][j-k],dp[to][k])); dp[u][j]=tmp; } } for(int i=m;i>=0;i--) { int tmp=dp[u][i]; for(int j=0;j<price[u].size();j++) if(price[u][j]<=i) { if(price[u][j]) dp[u][i]=max(dp[u][i],dp[u][i-price[u][j]]+power[u][j]); else dp[u][i]=max(dp[u][i],tmp+power[u][j]); } } } int main() { //freopen("in.txt","r",stdin); int t,x,y,q; scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); eg[x].push_back(y); eg[y].push_back(x); } scanf("%d",&m); for(int i=1;i<=n;i++) { scanf("%d",&q); while(q--) { scanf("%d%d",&x,&y); price[i].push_back(x); power[i].push_back(y); } } dfs(1,0); printf("%d\n",dp[1][m]); } return 0; }
然后又参考了网上的另一种做法,把每个节点每种花费的最大hp消耗存在数组里,写起来方便些,遍历的要多,时间复杂度要高一些,附上代码(998ms):
/* *********************************************** Author :devil Created Time :2016/3/29 16:58:28 ************************************************ */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <stdlib.h> using namespace std; #define inf 0x7f7f7f7f #define N 1010 #define M 210 int n,m,dp[N][M],hp[N][M]; vector<int>eg[N]; void init() { for(int i=0;i<N;i++) eg[i].clear(); memset(hp,0,sizeof(hp)); } void dfs(int u,int fa) { if(eg[u].size()==1&&u!=1) { for(int i=0;i<=m;i++) dp[u][i]=hp[u][i]; return ; } for(int i=0;i<=m;i++) dp[u][i]=inf; for(int i=0;i<eg[u].size();i++) { int to=eg[u][i]; if(to==fa) continue; dfs(to,u); for(int j=m;j>=0;j--) { int tmp=0; for(int k=0;k<=j;k++) tmp=max(tmp,min(dp[u][j-k],dp[to][k])); dp[u][j]=tmp; } } for(int i=m;i>=0;i--) for(int j=0;j<=i;j++) dp[u][i]=max(dp[u][i],dp[u][i-j]+hp[u][j]); } int main() { //freopen("in.txt","r",stdin); int t,x,y,q; scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); eg[x].push_back(y); eg[y].push_back(x); } scanf("%d",&m); for(int i=1;i<=n;i++) { scanf("%d",&q); while(q--) { scanf("%d%d",&x,&y); hp[i][x]=max(hp[i][x],y); } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) hp[i][j]=max(hp[i][j],hp[i][j-1]); dfs(1,0); printf("%d\n",dp[1][m]); } return 0; }