分组背包——HDU 3033 I love sneakers!

HDU 3033 I love sneakers!

题目

http://acm.hdu.edu.cn/showproblem.php?pid=3033
有K种运动鞋,N个鞋子(每个鞋最多只能买一次),总钱数为M,求不超过总钱数且每种鞋子至少买一双情况下的最大总价值。如果买不到所有种,就输出“Impossible”。
这个题的关键还是在于初始化,如果我们一开始把dp初始化为0,则当所有鞋子的价值都是0时,我们就无法区分是买不全那几款鞋子还是能买全但最大价值是0;因此,要把S!=0的dp[S][j]初始化为-1,便于区分。

输入输出

输入:
N(鞋个数)M(总钱数)K(鞋的种类数)
a(鞋种类号)b(鞋的价格)c(鞋的价值(得分))
多组数据
输出:
能获得的最大鞋的总价值
多组数据

思路

分组背包,外层循环组数。内层为01背包,两重循环。
dp[i][j]:第i种鞋子有j钱数能获取的最大鞋的总价值(不装满的情况)。
状态转移公式:dp[i][j]=max(dp[i][j],dp[i-1][j-price[i][l]]+value[i][l],dp[i][j-price[i][l]]+value[i][l])
当i=0时,dp[i][j]=0,当i!=0时,dp[i][j]=-100000(初始化第0组最大价值为0,其他组为-100000,因为b<100000)

注~

1.当i!=0时,dp为一个负数,则每一组对应dp必须有选取物品,即由其前面的组叠加来才不为负数。判断负数。

#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<algorithm>
#include<numeric>
#include<functional>
#include<memory>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<fstream>
#define min(a,b) (a)<(b)?(a):(b)
#define max(a,b) (a)>(b)?(a):(b)
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
const double pi=acos(-1.0);
const int INF=0x3f3f3f3f;
const int MAX=0x7fffffff;
const long long LINF=0x3f3f3f3f3f3f3f3f;
const long long LMAX=0x7fffffffffffffff;
const double eps=1e-9;
const int Mod=100007;
const int Max=10000005;
using namespace std;
int N,M,K;
vector<int> price[102];
vector<int> value[102];
int dp[12][10002];

int max3(int a,int b,int c){
    return (a)>(b)?((a)>(c)?(a):(c)):((b)>(c)?(b):(c)); 
}
int main() {
    freopen("data.in","r",stdin);
    cin.sync_with_stdio(false);
    cout.sync_with_stdio(false);
    while(cin>>N>>M>>K){
        memset(dp,0,sizeof(dp));
        for(int i=0;i<=K;++i){
            for(int j=0;j<=M;++j){
                if(i==0){
                    dp[i][j]=0;
                }else{
                    dp[i][j]=-100000;
                }
            }
        }
        for(int i=1;i<=K;++i){
            price[i].clear();
            value[i].clear();
        }
        int id,p,v;
        for(int i=0;i<N;++i){
            cin>>id>>p>>v;
            price[id].push_back(p);
            value[id].push_back(v);
        }


        for(int j=1;j<=K;++j){
            for(int l=0;l<price[j].size();++l){
                for(int i=M;i>=price[j][l];--i){
                    //cout<<"dp["<<j<<"]["<<i<<"]=max("<<"dp["<<j<<"]["<<i<<"]="<<dp[j][i]<<' '<<dp[j-1][i-price[j][l]]+value[j][l]<<' '<<dp[j][i-price[j][l]]+value[j][l]<<")"<<endl;
                    if(dp[j-1][i-price[j][l]]>=0||dp[j][i-price[j][l]]>=0)
                        dp[j][i]=max3(dp[j][i],dp[j-1][i-price[j][l]]+value[j][l],dp[j][i-price[j][l]]+value[j][l]); 
                }
            }
        }   

        if(dp[K][M]>=0)
            cout<<dp[K][M]<<endl;
        else
            cout<<"Impossible"<<endl;

    }

    fclose(stdin);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值