编程之美 1.6 买饮料问题

饮料供货

书中开始又是一堆看不懂的前述,感觉说了半天也没说清楚题目,看了解法一才看明白。
题目:假设STC共提供n中饮料,用(Si ,Vi,Ci,Hi,Bi )(对应的是饮料的名字,容量,可能的最大数量,满意度,实际购买量)来表示第i种饮料(i=0,1,…,n-1),其中可能的最大数量是指STC存货的上限。
基于如上表示:
饮料总容量为:
在这里插入图片描述
总满意度为:
在这里插入图片描述
那么题目要求就是,在满足条件∑_(i=0)(n-1)▒〖(V_i*B_i)〗=V的基础上求解max∑_(i=0)(n-1)▒〖(H_i*B_i)〗。
解题思路:

1. 动态规划

用Opt(V’,i)表示从第i,i+1,…n种饮料中,算出总量为V’的方案中满意度之和的最大值。
因此,Opt(V,1)中饮料就是我们要求值。
动态规划中心思想就是把大问题化解为小问题,先考虑当前的问题,即有
最优结果 = 选择k个第i种饮料的满意度 + 剩下的部分不考虑第i种饮料的最优结果
推导公式就是:
在这里插入图片描述
初始边界条件:
Opt(0,n)=0,即容量为0的情况下,最优化结果为0。
Opt(x,n)=-INF(负无穷)

2. 简单想法

在最大限制下购买最大单位满意度的饮料就行了,限制就是总容量和饮料的最大可能数量。
示例代码:

#include <iostream>

#include <iostream>
#define MAXV 100
#define MAXT 20
#define INF 0x7fffffff
#define N 7
using namespace std;

int v[N] = { 2,4,8,2,4,8,16 };
int c[N] = { 3,2,1,3,2,4,1 };
int h[N] = { 20,30,25,30,15,30,100 };

int opt[MAXV + 1][MAXT + 1];
// 记录每种饮料购买数量
int opt_num[MAXV + 1][MAXT + 1];
// 每种饮料的容量
int VV[MAXT];
// 每种饮料的容量上限(购买上限)
int CC[MAXT];
// 每种饮料的满意度
int HH[MAXT];
// 每种饮料的实际购买量
int BB[MAXT];

int T;

int Cal1(int V, int type)
{
	// 最后一种饮料
	if (type == T)
	{
		if (V == 0)
			return 0;
		else
			return -INF;
	}

	if (V < 0)
		return -INF;
	else if (V == 0)
		return 0;
	else if (opt[V][type] != -1)
		return opt[V][type];

	int ret = -INF;
	for (int i = 0; i <= CC[type]; i++)
	{
		int temp = Cal1(V - i*VV[type], type + 1);
		if (temp != -INF)
		{
			temp += HH[type] * i;
			if (temp > ret)
			{
				// 记录购买V升饮料,type类型的饮料的数量。
				opt_num[V][type] = i;
				ret = temp;
			}
		}
	}
	return opt[V][type] = ret;
}

int main()
{
	// 饮料总数
	int totle;
	// 总共的购买量
	T = N;
	totle = 64;

	for (int i = 0; i <= T - 1; i++)
	{
		VV[i] = v[i]; // 饮料的容量
		CC[i] = c[i]; // 容量
		HH[i] = h[i]; // 满意度
	}
	memset(opt, -1, sizeof(opt));
	int r = Cal1(totle, 0);

	// 下面输出每种饮料的实际供应量。 
	cout << "0:" << opt_num[totle][0] << endl;
	// 第0种饮料的数量(单位:个)
	int k = opt_num[totle][0];
	// t是饮料总供应量(单位:升)
	int mm = totle;
	// 依次计算第1种到第T-1种饮料的实际供应量
	for (int i = 1; i <= T; i++)
	{
		// mm-k*VV[i-1]是剩余饮料供应量(单位:升)
		int temp = opt_num[mm - k*VV[i - 1]][i];
		cout << i << ":" << temp << endl;
		mm -= k*VV[i - 1];
		// k保存当前饮料供应量
		k = temp;
	}
	cout << "最大的满意度:";
	cout << r << endl << endl;
	system("pause");
	return 0;
}

总结:还是动态规划,看来要暂时停止学习编程之美了,先去看看算法导论了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值