题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5445
题解:一看就像多重背包就是怎么看都不好做。但是这里有点明显的就是有两个背包,一个是糖果一个是箱子,于是不妨就试试两个多重背包,先考虑用这些糖果能否满足条件设dp[i]表示构成能量为i的糖果最小需要多少体积,然后将所需要的体积保存下来那么只要找到一些箱子总共能容纳的体积大于等于这个值就行这时的dp[i]又表示容积总共是i的箱子最少需要多少钱。其实这样也是不够严谨的因为这样也不能保证糖果刚好能放好但是理论上是可行的。还有要注意的就是多重背包要注意二进制的优化。
#include <iostream> #include <cstdio> #include <cstring> #define inf 0X3f3f3f3f using namespace std; const int M = 2e5 + 10; const int Max = 50000 + 10; int dp[M]; int t[M] , u[M] , v[M]; int x[M] , y[M] , z[M]; int main() { int test , n , m , q; scanf("%d" , &test); while(test--) { int ans = inf; scanf("%d%d%d" , &n , &m , &q); for(int i = 0 ; i < n ; i++) { scanf("%d%d%d" , &t[i] , &u[i] , &v[i]); } for(int i = 0 ; i < m ; i++) { scanf("%d%d%d" , &x[i] , &y[i] , &z[i]); } memset(dp , inf , sizeof(dp)); dp[0] = 0; for(int i = 0 ; i < n ; i++) { int mm = v[i]; for(int j = 1 ; mm > 0 ; j <<= 1) { int gg = min(j , mm); for(int l = Max ; l >= gg * t[i] ; l--) { dp[l] = min(dp[l] , dp[l - gg * t[i]] + gg * u[i]); } mm -= j; } } for(int i = q ; i <= Max ; i++) { if(dp[i] != inf) { ans = min(ans , dp[i]); } } memset(dp , 0 , sizeof(dp)); for(int i = 0 ; i < m ; i++) { int mm = z[i]; for(int j = 1 ; mm > 0 ; j <<= 1) { int gg = min(j , mm); for(int l = Max ; l >= gg * y[i] ; l--) { dp[l] = max(dp[l] , dp[l - gg * y[i]] + gg * x[i]); } mm -= j; } } int flag = 0; for(int i = 1 ; i <= Max - 10 ; i++) { if(dp[i] >= ans && ans != inf) { flag = i; break; } } if(flag) printf("%d " , flag); else printf("TAT "); } return 0; }