编程之美–饮料供货
共有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;
}