饮料供货问题

来源:互联网 发布:xp笔记本怎么共享网络 编辑:程序博客网 时间:2024/04/29 00:28

题目:在微软亚洲研究院上班,大家早上来的第一件事是干啥呢?查看邮件?No,是去水房拿饮料:酸奶,豆浆,绿茶、王老吉、咖啡、可口可乐……(当然,还是有很多同事把拿饮料当做第二件事)。

管理水房的阿姨们每天都会准备很多的饮料给大家,为了提高服务质量,她们会统计大家对每种饮料的满意度。一段时间后,阿姨们已经有了大批的数据。某天早上,当实习生小飞第一个冲进水房并一次拿了五瓶酸奶、四瓶王老吉、三瓶鲜橙多时,阿姨们逮住了他,要他帮忙。

从阿姨们统计的数据中,小飞可以知道大家对每一种饮料的满意度。阿姨们还告诉小飞,STC(Smart Tea Corp.)负责给研究院供应饮料,每天总量为V。STC很神奇,他们提供的每种饮料之单个容量都是2的方幂,比如王老吉,都是23=8升的,可乐都是25=32升的。当然STC的存货也是有限的,这会是每种饮料购买量的上限。统计数据中用饮料名字、容量、数量、满意度描述每一种饮料。

那么,小飞如何完成这个任务,求出保证最大满意度的购买量呢?

解法一: 动态规划

先进行数学建模:

假设STC共提供n种饮料,用(Si, Vi, Ci,Hi,Bi)(对应饮料名、容量、可能的最大数量、满意度、实际购买量)来表示第i种饮料(i =0,1,。。,n-1),其中可能的最大数量指如果仅买某种饮料的最大可能数量。

基于如上公式:饮料总容量为 V1*B1+V2*B2+...+Vn*Bn  总满意度为H1*B1+H2*B2+...+Hn*Bn

那么题目的要求就是,在满足V1*B1+V2*B2+...+Vn*Bn=V的基础上,求解max(H1*B1+H2*B2+...+Hn*Bn)

用Opt(V', i) 表示从第i,i+1,i+2,...,n-1种饮料中,算出总量为V'的方案中满意度之和的最大值。因此,Opt(V,0)就是我们要求的值。

那么,可以列出如下的推导公式:Opt(V',i) = max {k*Hi + Opt(V'-k*Vi, i+1)}  k=0,1,..., Ci, i=0, 1, ..., n-1

初始边界条件: Opt(0, n) = 0 容量为0的情况下,最优化结果为0。

                         Opt(x, n) = -INF (x!=0) 容量不为0的情况下,把最优化结果设为负无穷大,并把它作为初值。

根据推导公式,动态规划求解代码如下:

/* * Drink.h * *  Created on: 2014年2月8日 *      Author: Eileen */#ifndef DRINK_H_#define DRINK_H_namespace std {class Drink {public:Drink();virtual ~Drink();int Cal(int*, int*, int*);static const int N = 3;  //饮料种数static const int V = 8;  //总容量数int V[] = {1, 1, 1};int H[] = {1, 10, 100};int C[] = {10, 2, 2};int (*result)[N+1] = new int[V+1][N+1];void PrintDrink(int*);};} /* namespace std */#endif /* DRINK_H_ */
/* * Drink.cpp * *  Created on: 2014年2月8日 *      Author: Eileen */#include "Drink.h"#include <iostream>using  namespace std;Drink::Drink() {// TODO Auto-generated constructor stubfor(int i=0; i<=V; i++)for(int j=0; j<=N; j++){result[i][j] = 0;}}Drink::~Drink() {// TODO Auto-generated destructor stub}int Drink::Cal(int* VArray, int* HArray, int* CArray){//VArray为容量数组, HArray为满意度数组, CArray为最大数量数组//V为总容量数,N为饮料总数int (*opt)[N+1] = new int[V+1][N+1];opt[0][N] = 0;for (int i=0; i<=V; i++)for (int j=0; j<=N; j++){opt[i][j] = INF;}for(int i=N-1; i>=0; i--){for(int j=1; j<=V; j++){for(int k=0; k<=CArray[i];k++){if(j < k*VArray[i])break;if((k*HArray[i]+opt[j-k*VArray[i]][i+1])>opt[j][i]){opt[j][i] = k*HArray[i]+opt[j-k*VArray[i]][i+1];result[j][i] = k;}}}}return opt[V][0];}void Drink::PrintDrink(int* VArray){int V1=V;for(int i=0; i<=N-1; i++){cout<<result[V1][i]<< " ";V1 -= result[V1][i]*VArray[i];}}


0 0
原创粉丝点击