背包问题

本文详细解析了01背包问题的定义及应用实例,通过一个关于饭卡余额使用的具体问题来展示如何运用01背包算法解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

01背包问题:

N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

从这个题目中可以看出,01背包的特点就是:每种物品仅有一件,可以选择放或不放。

其状态转移方程是:

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

对于这方方程其实并不难理解,方程之中,现在需要放置的是第i件物品,这件物品的体积是c[i],价值是w[i],因此:

f[i-1][v]代表的就是不将这件物品放入背包,而f[i-1][v-c[i]]+w[i]则是代表将第i件放入背包之后的总价值,比较两者的价值,得出最大的价值存入现在的背包之中。

实例分析

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=2546

题目描述

Problem Description

电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。

 

Input

多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000
第二行包括n个正整数,表示每种菜的价格。价格不超过50
第三行包括一个正整数m,表示卡上的余额。m<=1000

n=0表示数据结束。

 

Output

对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。

 

Sample Input

1

50

5

10

1 2 3 2 1 1 2 3 2 1

50

0

 

Sample Output

-45

32


题目大意

如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。要求使卡上的余额尽可能的最少。

解题思路

很经典的一道01背包题,要注意的是这里只要剩余的钱不低于5元,就可以购买任何一件物品,所以5在这道题中是很特许的,再使用01背包之前,我们首先要在现在所拥有的余额中保留5元,用这五元去购买最贵的物品,而剩下的钱就是背包的总容量,可以随意使用。

AC代码:

#include <stdio.h>
#include <string.h>
int val[1010],cai[1010];
int n,m;
int main()
{
    int max,num,i,j;
    while(scanf("%d",&n),n)
    {
        memset(val,0,sizeof(val));
        memset(cai,0,sizeof(cai));
        for(i=0;i<n;i++)
            scanf("%d",&cai[i]);
        max=cai[0];
        num=0;
        for(i=1;i<n;i++)
            if(max<cai[i])
            {
                max=cai[i];
                num=i;
            }
        scanf("%d",&m);
        if(m<5)
        {
            printf("%d\n",m);
            continue;
        }
        for(i=0;i<n;i++)
        {
            if(i==num)
                continue;
            for(j=m-5;j>=cai[i];j--)
                if(val[j-cai[i]]+cai[i]>val[j])
                    val[j]=val[j-cai[i]]+cai[i];
        }
        printf("%d\n",m-val[m-5]-max);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值