HDU 5445 Food Problem (2015年长春站网络赛1009 多重背包DP)

这道题给我最大的启示就是学习一定要脚踏实地!!!原来我觉得背包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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值