POJ 1149 (0-1背包变形)

0-1背包(商品组合)

题意:

有n种(最多5种)商品,每种商品三个属性,自己的名字(数字),总量,价钱。现在商家正在进行打折活动,几种商品组合的价钱会比原价低。有s种组合每种组合第一个数字是有n种商品组合成一起,然后n对数字

代表商品的名字和数量,最后一个数字表示这个组合的总价钱。

最后输出,要买所有商品最少花多少钱?

思路:

每种商品都要买,这是0-1背包问题,但是问题是怎么把每种组合算在其中。

解决的办法是把每一种组合当做一个商品,我们记录每一种组合中的商品个数,我们如果选择了这一个商品,就会减去相应物品的个数与之比较。

dp[a][b][c][d][e]
表示五种商品分别买的个数花费的最少钱数。
  • 注意一个点:每一个商品的名字很大,这道题可以用数组开出来,其实即使更大我们可以用map标记,进行离散化。

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 100;

struct goods
{
    int code,cnt,price;
}g[6];

const int INF = 0x3f3f3f3f;

int n,s;
int dp[6][6][6][6][6];
int p[maxn][maxn*10+5];     //表示组合i,花费物品j的个数
int reduced[maxn];

int main()
{
    //freopen("in.txt","r",stdin);

    scanf("%d",&n);
    for(int i = 1;i <= n; i++) {
        scanf("%d%d%d",&g[i].code,&g[i].cnt,&g[i].price);
    }
    scanf("%d",&s);
    for(int i = 1;i <= s; i++) {
        int goods_cnt;
        scanf("%d",&goods_cnt);
        for(int j = 1;j <= goods_cnt; j++) {
            int tcode,tcnt;
            scanf("%d%d",&tcode,&tcnt);
            p[i][tcode] = tcnt;
        }
        scanf("%d",&reduced[i]);
    }
    for(int a = 0;a <= g[1].cnt; a++) {
        for(int b = 0;b <= g[2].cnt; b++) {
            for(int c = 0;c <= g[3].cnt; c++) {
                for(int d = 0;d <= g[4].cnt; d++) {
                    for(int e = 0;e <= g[5].cnt; e++) {
                        dp[a][b][c][d][e] = 
                            a*g[1].price + b*g[2].price 
                            + c*g[3].price + d*g[4].price +
                            e*g[5].price;
                        for(int i = 1;i <= s; i++) {
                            int a1 = a - p[i][g[1].code];
                            int b1 = b - p[i][g[2].code];
                            int c1 = c - p[i][g[3].code];
                            int d1 = d - p[i][g[4].code];
                            int e1 = e - p[i][g[5].code];
                            if(a1 < 0 || b1 < 0 || c1 < 0 || d1 < 0 || e1 < 0) continue;
                            int temp = dp[a1][b1][c1][d1][e1] + reduced[i];
                            dp[a][b][c][d][e] = min(dp[a][b][c][d][e],temp);
                        }
                    }
                }
            }
        }
    }
    printf("%d\n",dp[g[1].cnt][g[2].cnt][g[3].cnt][g[4].cnt][g[5].cnt]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值