题意:一棵树,从根过来一支攻击流,你可以在任意节点建防御点(有多重配置),防御点可以削减攻击强度,到叶节点的总削减值就算叶节点的防御强度
你的目标是让所有叶节点中防御强度最低的点,防御值最高
设dp[i][j]表示i节点分配j资源得到的最大防御强度
显然dp[i][j]由i节点防御值和i的子树防御值加和得到
所以把j分为两部分给节点和子树,则可得到最优解
一次dfs,对每次遍历到的点u做2次dp,
第一次:开maxsum[m]数组,存储u的所有儿子在分配[0~m]资源时的最优解
第二次:用maxsum[m]的值来更新dp[i][j]:枚举j的数值,m-j给子树,j给i点
代码:
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<queue> #include<string> #include<vector> #include<set> #include<math.h> #include<map> #define ull unsigned long long #define ll long long #define mp map #define FOR(a,b) for(int i=a;i<=b;i++) #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 using namespace std; int m; const int maxm = 210; const int maxn = 1010; vector<int>aaa[maxn]; int weaponChoice[maxn]; int cost[maxn][52]; int power[maxn][52]; int dp[maxn][maxm]; //dp[i][j]:i与其子树消耗j资源的最薄弱链最大值 void dfs(int u,int fa){ for(int i=m;i>=0;i--){ for(int j=1;j<=weaponChoice[u];j++){ if(cost[u][j]<=i)dp[u][i]=max(dp[u][i],power[u][j]); } } if(aaa[u].size()==1&&u!=1)return; int maxson[maxn]; //maxson[i]:u子树花费资源i时最大值 memset(maxson,0x3f3f3f3f,sizeof(maxson)); for(int e=0;e<aaa[u].size();e++){//枚举u的子节点 int v=aaa[u][e]; if(v==fa)continue; dfs(v,u); //计算v树的最优解,dp[v]系 for(int i=m;i>=0;i--){ //枚举给u子树分配的资源 int maxx=0; for(int j=0;j<=i;j++){ maxx=max(maxx,min(maxson[i-j],dp[v][j])); //其他子树分i-j,v树分j } maxson[i]=maxx; } } for(int i=m;i>=0;--i){ for(int k=0;k<=i;++k){ dp[u][i]=max(dp[u][i],dp[u][i-k]+maxson[k]); } } } int main(){ int tcase; scanf("%d",&tcase); while(tcase--){ memset(dp,0,sizeof(dp)); int n; scanf("%d",&n); for(int i=0;i<=n;i++)aaa[i].clear(); int a,b; for(int i=1;i<n;i++){ scanf("%d %d",&a,&b); aaa[a].push_back(b); aaa[b].push_back(a); } scanf("%d",&m); for(int i=1;i<=n;i++){ scanf("%d",&weaponChoice[i]); for(int j=1;j<=weaponChoice[i];j++){ scanf("%d %d",&a,&b); cost[i][j]=a;power[i][j]=b; } } dfs(1,-1); printf("%d ",dp[1][m]); } }
--------------------------------------------------
一篇很好的博客:http://blog.csdn.net/u011836218/article/details/39084365
很好的分析了子节点的状态转移
分析方法值得借鉴