编程之美饮料供货:动态规划解法

编程之美–饮料供货

共有n种饮料,每种饮料都有自己的名字、1瓶这种饮料对应的容量(单位:L)、可供应这种饮料的最大数量、以及1瓶此种饮料的满意度、实际购买这种饮料的瓶数。

我们定义一个表示饮料的结构体。分别用name、capacity、maxNumber、happiness、purchaseNumber对应以上属性。

问题要求:给定可提供饮料的最大供应量totalSupport(单位为L),要求饮料购买方案,使得购买方案对应的满意度最大。

解决方法:

应用动态规划求解,

假设用satisfy[n][L]表示在最大供应量为L的情况下,选择前n种饮料是的购买方案对应的最大满意度。则

satisfy[i][j] 就表示在最大供应量为j的情况下,选择前i中饮料的购买方案对应的最大满意度,并且有:

如果 j < capacity;satisfy[i][j] = satisfy[i – 1][j]

如果 j > capacity;satisfy[i][j] = max{satisfy[i – 1][j – k * capacity] + k * happiness, k = 0, 1, 2, 3, …, maxNumber,并且k要使得 j-k * capacity >= 0}。这个式子最直观的解释就是,提供最大供应量j,在前i种饮料中选择。并且最大供应量j大于单位体积的第j种饮料。那么对于第j种饮料,我可以分别考虑买0、1、2、…瓶第j种饮料的情况。然后选择一个使满意度最大的购买方案。

上面就是动态规划方法递推公式。用上面的公式,就可以建立表格了!

#include <iostream>
#include <vector>
#include <string>
using namespace std;

struct Goods{
	string name;//饮料的名字名字
	int capacity;//单位饮料的容量,单位:L
	int maxNumber;//可供应饮料的最大数量,单位:个
	int happiness;//对单位饮料的满意度
	int purchaseNumber;//对饮料的实际购买数量,单位:个
	Goods() : name(20, '0'), capacity(0), maxNumber(0), happiness(0), purchaseNumber(0){
	}
};

//输入饮料信息
void getGoodsInformation(vector<Goods> &goods){
	size_t n = goods.size();
	if (n == 0){
		return;
	}
	cout << "请依次输入饮料的名称、单位饮料的容量、可供应此种饮料的最大数量、对此种饮料的满意度:";
	for(size_t i = 0; i != n; i++){
		cin >> goods[i].name >> goods[i].capacity >> goods[i].maxNumber >> goods[i].happiness;
	}
	return;
}
//输出达到最大满意度的饮料购买方案
void getAndPrintBuy(vector<Goods> &goods, vector<vector<int> > &state, vector<int> &buy, int totalSupport){
	int theNumberofGoods = buy.size();
	for(int i = theNumberofGoods - 1; i >= 0; i--){
		if (totalSupport == 0){
			break;
		}
		int k = state[i+1][totalSupport];
		buy[i] = k;
		totalSupport -= (k * goods[i+1-1].capacity);
	}
	cout << endl << "饮料购买方案为:" << endl;
	for(int i = 0; i < theNumberofGoods; i++){
		cout << "饮料名:" << goods[i].name << " 购买数量:"<< buy[i] << endl;
	}
}
//使用动态规划求解
int getMaxSatisfy(vector<Goods> &goods, int totalSupport){
	//定义二维数组satisfy
	int theNumberofGoods = goods.size();//饮料的种类
	vector<vector<int> > satisfy(theNumberofGoods + 1, vector<int> (theNumberofGoods + 1, 0));
	vector<vector<int> > state(theNumberofGoods + 1, vector<int> (theNumberofGoods + 1, -1));

	//初始化边界条件
	for(int i = 0; i <= theNumberofGoods; i++){
		satisfy[i][0] = 0;
	}
	for(int j = 0; j <= totalSupport; j++){
		satisfy[0][j] = 0;
	}

	for(int i = 1; i <= theNumberofGoods; i++){
		for(int j = 1; j <= totalSupport; j++){
			int maxHappiness = 0;
			int purchaseNumber = 0;
			for(int k = 0; k <= goods[i - 1].maxNumber; k++){
				if(goods[i-1].capacity * k > j){
					break;
				}
				int temp = 0;
				temp = satisfy[i - 1][j - k * goods[i-1].capacity] + k * goods[i-1].happiness;
				if (temp > maxHappiness){
					maxHappiness = temp;
					purchaseNumber = k;
				}
			}
			satisfy[i][j] = maxHappiness;
			state[i][j] = purchaseNumber;
		}
	}
	//输出satisfy矩阵
	for(int i = 0; i <= theNumberofGoods; i++){
		for(int j = 0; j <= totalSupport; j++){
			cout << satisfy[i][j] << " ";
		}
		cout << endl;
	}
	vector<int> buy(theNumberofGoods, 0);
	getAndPrintBuy(goods, state, buy, totalSupport);
	return satisfy[theNumberofGoods][totalSupport];
}

int main(void){
	int n;
	cout << "输入商品的种类n" << endl;
	cin >> n;
	vector<Goods> vec(n);
	getGoodsInformation(vec);
	int max = 0;
	int totalSupport;//总的饮料提供量, 单位:L
	cout << "输入总的饮料提供量,单位为L:" << endl;
	cin >> totalSupport;
	max = getMaxSatisfy(vec, totalSupport);
	cout << "最大满意度为:" << max << endl;
	return 0;
}

    原文作者:wly_2014
    原文地址: https://blog.csdn.net/wly_2014/article/details/51438232
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞