对于分组背包,每组选且只选一件商品的写法只想出了二维数组的写法。
dp[s][k] 表示 在前s类中选取价格为 k 的商品的最优解。
dp[s][k] = max( dp[s-1][k-product[s][j].c] + product[s][j].w)。dp[s][k]每次只会有dp[s-1]更新得到,保证了前s-1类商品的选取。
对于此题,可以把每棵子树的情况看成一类商品,递归求解。
dp[s][k]表示在s子树上投入k个机器人时的最优解。
当k == 0时,表示在s点投入1个机器人,且此机器人又返回s点,当k >= 1时,表示在s点投入k个机器人且都不返回的s结点时的最优解。
更新时显而易见的有,每棵子树选取一种情况下最优解来更新根节点的最优解。写法即为上面的二位分组背包,但是此题貌似范围较大建议滚动数组。
#include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <cmath> #include <stack> #include <map> #pragma comment(linker, "/STACK:1024000000"); #define EPS (1e-8) #define LL long long #define ULL unsigned long long LL #define _LL __int64 #define _INF 0x3f3f3f3f #define Mod 1000000007 #define LM(a,b) (((ULL)(a))<<(b)) #define RM(a,b) (((ULL)(a))>>(b)) using namespace std; const LL MAXN = 10010; struct N { int u,v,w,next; } edge[MAXN*2]; int head[MAXN]; int Top; void Link(int u,int v,int w = -1) { edge[Top].u = u; edge[Top].v = v; edge[Top].w = w; edge[Top].next = head[u]; head[u] = Top++; } void Init_head_Top(int n) { memset(head,-1,sizeof(int)*(n+2)); Top = 0; } int dp[12][MAXN]; int dfs(int s,int pre,int k) { if(dp[k][s] != -1) return dp[k][s]; int val[2][14]; memset(val,-1,sizeof(val)); int site = 1; bool mark = false; for(int p = head[s]; p != -1; p = edge[p].next) { if(edge[p].v != pre) { if(mark == false) { mark = true; memset(val[site&1],-1,sizeof(val[site&1])); for(int j = 0; j <= k; ++j) { int t = dp[j][edge[p].v] == -1 ? dfs(edge[p].v,s,j) : dp[j][edge[p].v]; if(j == 0) val[site&1][j] = t + edge[p].w*2; else val[site&1][j] = t + edge[p].w*j; } } else { memset(val[site&1],-1,sizeof(val[site&1])); for(int i = 0; i <= k; ++i) { if(val[(site-1)&1][i] != -1) { for(int j = k; j >= 0; --j) { if(i+j <= k) { int temp; int t = dp[j][edge[p].v] == -1 ? dfs(edge[p].v,s,j) : dp[j][edge[p].v]; if(j == 0) temp = t + edge[p].w*2 + val[(site-1)&1][i]; else temp = t + edge[p].w*j + val[(site-1)&1][i]; if(val[site&1][i+j] == -1 || val[site&1][i+j] > temp) val[site&1][i+j] = temp; } } } } } site++; } } for(int i = 0;i <= k; ++i) { if(val[(site-1)&1][i] != -1) dp[i][s] = val[(site-1)&1][i]; else dp[i][s] = 0; } // cout<<"k = "<<k<<" s = "<<s<<" dp = "<<dp[k][s]<<endl; return dp[k][s]; } int main() { int n,s,k; int u,v,w; while(scanf("%d %d %d",&n,&s,&k) != EOF) { Init_head_Top(n); for(int i = 0; i <= k; ++i) { memset(dp[i],-1,sizeof(int)*(n+2)); } for(int i = 1; i < n; ++i) { scanf("%d %d %d",&u,&v,&w); Link(u,v,w); Link(v,u,w); } dfs(s,-1,k); int Min = dp[1][s]; for(int i = 1; i <= k; ++i) { Min = min(Min,dp[i][s]); // cout<<"dp = "<<dp[i][s]<<endl;; } printf("%d\n",Min); } return 0; }