递归——凑单

描述
消费者为了享受商家发布的满减优惠,常常需要面临凑单问题。

假设有n件商品,每件的价格分别为p1,p2,...,pn,每件商品最多只能买1件。为了享受优惠,需要凑单价为t。那么我们要找到一种凑单方式,使得凑单价格不小于t(从而享受优惠),同时尽量接近t。被称为“最佳凑单”

如果不存在任何一种凑单方式,使得凑单价格不小于t(即无法享受优惠),那么最佳凑单不存在。

比如当前还差10元享受满减,可选的小件商品有5件,价格分别为3元、5元、8元、8元和9元,每件商品最多只能买1件。那么当前的最佳凑单就是11元(3元+8元)。
 
关于输入
第一行输入商品数n(n<=10)和需要凑单价t,如:
5 10
第二行输入每件商品的价格,如:
3 5 8 8 9
 
关于输出
如果可以凑单成功,则输出最佳凑单的价格,如:
输入
5 10
3 5 8 8 9
输出
11

如果无法凑单成功,则输出0。

如输入
5 10
1 1 1 1 1
则无法凑够10元,输出
0
例子输入
5 10

3 5 8 8 9
例子输出
11
提示
1. 为了简化问题,本题中每件商品最多只能买1件。
2. 不同的商品,即使价格相同也可以都买。比如5件商品,价格分别为3元、5元、8元、8元和9元。你可以买 8元(第3件)+8元(第4件)

做法1:k个商品凑t元=min(不选第k个 剩下k-1个凑t,选第k个 剩下k-1个凑t减去k的价值)
边界!!k=0:比较第一个商品价值与此时的额度money

#include<iostream>	
using namespace std;
int value[10] = {};
int n, t;
int f(int money, int k)//挑选前k个商品,要凑的额度是money,凑单结果是返回值
{
	if (k == 0 && value[0] < money)return 0;//额度没用完,也就是没凑齐,由题意返回0
	if (k == 0 && value[0] >= money)return value[0];//凑齐了,返回当前凑单的值
	int a = f(money, k - 1);//不选第k个产品的凑单价值
	int b = f(money - value[k], k - 1) + value[k];//选第个产品的凑单价值
	if (a < money && b < money)return 0;//如果都没能凑成额度,返回0
	else if (a >= money && b < money)return a;//只有a可以,那么直接返回a
	else if (a < money && b >= money)return b;
	else if (a >= money && b >= money)return (a < b ? a : b);//都可以,返回较小的那一个
}
int main() {
	cin >> n >> t;
	for (int i = 1; i <= n; ++i) {
		cin >> value[i];
	}
	cout << f(t, n);
	return 0;
}

做法2:尝试所有可能的凑法并记录,再比较

#include<iostream>
#include<algorithm>
using namespace std;
int n, t, num = 0;
int cost[11] = {};
int money[200] = {};
void f(int x, int y)//第x个商品,已凑y元
{
	if (y >= t) {//如果凑够了,将这种凑法的价格记录并返回
		money[num++] = y;
		return;
	}
	if (x == n) {//如果所有商品均尝试,返回
		return;
	}
	f(x + 1, y + cost[x]);//选择第x个商品,继续凑单
	f(x + 1, y);//选择第x个商品,继续凑单
}
int main()
{
	cin >> n >> t;
	for (int i = 0; i < n; ++i) {
		cin >> cost[i];
	}
	f(0, 0);//从第一个商品开始凑单,初始0元
	sort(money, money + num);//将所有凑单价格排序
	if (money[0]) {
		cout << money[0];
	}
	else cout << 0;
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值