专栏文章

题解:B3873 [GESP202309 六级] 小杨买饮料

B3873题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mip5ulxt
此快照首次捕获于
2025/12/03 06:39
3 个月前
此快照最后确认于
2025/12/03 06:39
3 个月前
查看原文

前言

一道非常简单的 01 背包变形。

简述

小杨来到一家商店买饮料,商店有 NN 种饮料,编号 00N1N-1。第 ii 种饮料的价格是 cic_i 元,容量是 lil_i 毫升。小杨的要求是:
  1. 每种饮料最多买 11 瓶。
  2. 购买的饮料总容量至少为 LL 毫升。
  3. 在满足前两个条件的情况下花费最少。
如果无法满足条件,输出 no solution

本题思路

本题是一个相对简单的背包,目标是选择若干种不同的饮料,使得它总容量至少为 LL 毫升,并且总花费最小。
由于每种饮料只有选或不选两种情况,可以用 01背包求解。
首先,定义 dpi,jdp _ {i,j} 表示 从前 ii 种饮料中选择,使得总容量至少为 jj 毫升时的最小花费。
初始化时,要使 dp[0][0]=0(什么也不选也是 11 种方案),dpdp 数组其余设为无穷大(因为要找最小值)。
接下来,遍历每种饮料,并考虑选或不选它:
1.不选第 ii 种饮料:dp[i][j] = dp[i-1][j],直接从之前的状态继承。
2.选第 ii 种饮料:
如果该饮料的容量 l[i]l[i] 已经满足 jj,则只需要花费 c[i]c[i] 元。否则,还需要从前 i1i-1 种饮料中补充 jl[i]j-l[i] 的容量,即 dp[i][j]=dp[i-1][j-l[i]]+c[i]
当然,为了避免 jl[i]j-l[i] 为负数,我们取 prev=max(0,j-l[i]),确保剩余需求不会小于 00
最终,dp[N][L]dp[N][L] 就是答案:如果它仍然是无穷大,说明无法满足需求,输出 no solution;否则,输出 dp[N][L]dp[N][L]

代码

CPP
#include<bits/stdc++.h>
using namespace std;
int N,L,c[505],l[505],dp[505][2005]//前 i 种饮料中选,使得总容量至少为 j 毫升时的最小花费。
int main(){
	cin>>N>>L;
	for(int i=1;i<=N;i++){
		cin>>c[i]>>l[i];
	}
	memset(dp,0x3f,sizeof(dp));
	dp[0][0]=0;//什么也不选也是 1 种方案。 
	for(int i=1;i<=N;i++){
		for(int j=0;j<=L;j++){
			//不选。 
			 dp[i][j]=dp[i-1][j];
            //选第 i 种饮料。
            int prev=max(0,j-l[i]);//目标不是恰好装满,而是至少达到 L 容量。
            if(dp[i-1][prev]+c[i]<dp[i][j]){
                dp[i][j]=dp[i-1][prev]+c[i];
            }
		} 
	}
	if(dp[N][L]!=0x3f3f3f3f){//被更新。 
		cout<<dp[N][L];
	}else{
		cout<<"no solution";//未被更新。
	}
	return 0;
} 

评论

0 条评论,欢迎与作者交流。

正在加载评论...