这道题给我最大的启示就是学习一定要脚踏实地!!!原来我觉得背包DP应该是随手写的,赛场上并没有看这题,今天打算再补补题,发现这道裸的背包DP居然不怎么会写,然后默默地又把背包DP翻了一下。。。
题目很简单:总的来说做两次背包就搞定了。
两个模型:
1:n个物品,每个物品价值为t[i],占的空间为u[i],数量为v[i],要取其中的某些物品使得总价值>=p,所占空间最小。
2:m个物品,每个物品价值为x[i],占空间为y[i],数量为z[i],一个空间为50000的背包,问所有的dp[i](i的空间最多能放多大价值的物品)。
具体做法:1:算出最小的空间V。2:算出所有的dp[i],然后o(n)扫一遍找出最小的i满足dp[i] >= V。题目做完。因为没看到做多花50000,wa了2发
下面是AC代码:
#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
using namespace std;
const int maxn = 220;
const int maxm = 220;
const int maxp = 50050;
const int inf = 0x3fffffff;
int dp[maxp];
void ZeroOne_Pack(int cost,int weight,int n,bool flag){
if(!flag) IFOR(i,n,cost-1) dp[i] = min(dp[i],dp[i-cost]+weight);
else IFOR(i,n+1,cost-1) dp[i] = max(dp[i],dp[i-cost]+weight);
}
void Complete_Pack(int cost,int weight,int n,bool flag){
if(!flag) FOR(i,cost,n+1) dp[i] = min(dp[i],dp[i-cost]+weight);
else FOR(i,cost,n+1) dp[i] = max(dp[i],dp[i-cost]+weight);
}
void Multi_Pack(int* c,int* w,int* num,int n,int m,bool flag){
if(!flag) {FOR(i,0,m+1) dp[i] = inf;dp[0] = 0;}
else {FOR(i,0,m+1) dp[i] = 0;}
FOR(i,0,n){
if(num[i] * c[i] > m) {Complete_Pack(c[i],w[i],m,flag);continue;}
int k = 1;
while(k < num[i]){
ZeroOne_Pack(k*c[i],k*w[i],m,flag);
num[i] -= k;
k <<= 1;
}
ZeroOne_Pack(num[i]*c[i],num[i]*w[i],m,flag);
}
}
int t[maxn],u[maxn],v[maxn];
int x[maxm],y[maxm],z[maxm];
void work(){
int n,m,p;
scanf("%d%d%d",&n,&m,&p);
FOR(i,0,n) scanf("%d%d%d",&t[i],&u[i],&v[i]);
Multi_Pack(t,u,v,n,p+100,false);
int res = inf;
FOR(i,p,p+101) res = min(res,dp[i]);
FOR(i,0,m) scanf("%d%d%d",&x[i],&y[i],&z[i]);
Multi_Pack(y,x,z,m,50000,true);
int ans = -1;
FOR(i,0,50001){
if(dp[i] >= res) {ans = i;break;}
}
if(ans == -1) printf("TAT\n");
else printf("%d\n",ans);
}
int main(){
//freopen("test.in","r",stdin);
int T;
scanf("%d",&T);
while(T--){
work();
}
return 0;
}