编程之美(六)饮料供货

在微软亚洲研究院上班,大家早上来的第一件事是干啥呢?查看邮件?No

No,是去水房拿饮料:酸奶,豆浆,绿茶、王老吉、咖啡、可口可乐……(当然,还是有很多同事把拿饮料当做第二件事)。

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

从阿姨们统计的数据中,小飞可以知道大家对每一种饮料的满意度。阿姨们还告诉小飞,STC

STC(SmartTeaCorp.SmartTeaCorp.)负责给研究院供应饮料,每天总量为VV。STCSTC很神奇,他们提供的每种饮料之单个容量都是22的方幂,比如王老吉,都是23=823=8升的,可乐都是25=3225=32升的。当然STC

STC的存货也是有限的,这会是每种饮料购买量的上限。统计数据中用饮料名字、容量、数量、满意度描述每一种饮料。

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

分析:动态规划

每种饮料由五个关键参数来描述Si,Vi,Ci,Hi,Bi

Si,Vi,Ci,Hi,Bi (分别对应的是饮料名字、容量、可能的最大数量、满意度、实际购买量)来表示第ii种饮料(i=0,1,...,n1

i=0,1,...,n1)

那么饮料总容量为n1i=0

i=0n1(ViBiViBi),总满意度为n1i=0i=0n1(HiBiHiBi)
那么题目的要求就是,在满足条件n1i=0i=0n1(ViBi)=VViBi)=V的基础上,求解maxmax{n1i=0i=0n1(HiBi

HiBi)}

考虑用动态规划求解:用opt(V,i)

opt(V,i)表示从ii开始到n1n1种饮料,算出总量为V

V‘的方案中满意度之和的最大值

  • opt(V,0)
  • opt(V,0)即表示我们所要求的值
  • 假设我们选择k
k杯ii种饮料,那么我们所得的满意度即为kH[i]+opt[VkH[i]][i+1]opt[V][i]=max(kH[i]+opt[VkH[i]][i+1])
  • kH[i]+opt[VkH[i]][i+1]opt[V][i]=max(kH[i]+opt[VkH[i]][i+1])
  • 初始化边界条件:(1) opt[0][n]=0
opt[0][n]=0,表示容量为00的情况下,最优化结果为00 (2) opt[x][n]=INFopt[x][n]=INF(INFINF为负无穷大),即在容量不为 0 0的情况下,把最优化结果设为负无穷大,并将其作为初值

动态规划代码


int Cal(int V, int T) { //边界条件初始化 opt[0][T] = 0; for (int i = 1; i <= V; ++i) { opt[i][T] = -INF; } for (int j = T - 1; j >= 0; --j) { for (int i = 0; i <= V; ++i) { opt[i][j] = -INF; for (int k = 0; k <= c[j]; ++k) { //选取第j种饮料数量为k if (i < k * v[j]) break; int x = opt[i - k * v[j]][j + 1]; if (x != -INF) { x += k * h[j]; if (x > opt[i][j]) { opt[i][j] = x; opt_num[i][j] = k; //保存选取第j种饮料的数量 } } } } } return opt[V][0]; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

备忘录法:打表

用一个表格来保存已解决的子问题的答案,并通过记忆化搜索的方式来避免计算一些不可能到达的状态


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 <= c[type]; ++i) { int temp = Cal1(V - i * v[type], type + 1); if (temp != -INF) { temp += i * h[type]; if (temp > ret) { opt_num[V][type] = i; ret = temp; } } } return opt[V][type] = ret; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

测试代码


#include <iostream> #define MAXV 100 #define MAXT 20 #define INF 0x7fffffff #define N 7 using namespace std; int V = 64; 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 T; /* int Cal(int V, int T) { opt[0][T] = 0; for (int i = 1; i <= V; ++i) { opt[i][T] = -INF; } for (int j = T - 1; j >= 0; --j) { for (int i = 0; i <= V; ++i) { opt[i][j] = -INF; for (int k = 0; k <= c[j]; ++k) { if (i < k * v[j]) break; int x = opt[i - k * v[j]][j + 1]; if (x != -INF) { x += k * h[j]; if (x > opt[i][j]) { opt[i][j] = x; opt_num[i][j] = k; } } } } } return opt[V][0]; }*/ 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 <= c[type]; ++i) { int temp = Cal1(V - i * v[type], type + 1); if (temp != -INF) { temp += i * h[type]; if (temp > ret) { opt_num[V][type] = i; ret = temp; } } } return opt[V][type] = ret; } int main() { T = N; int ret = Cal1(V, 0); cout << "0:" << opt_num[V][0] << endl; int k = opt_num[V][0]; int m = V; for (int i = 1; i <= T - 1; ++i) { int temp = opt_num[m - k * v[i - 1]][i]; cout << i << ":" << temp << endl; m -= k * v[i - 1]; k = temp; } cout << ret << endl; return 0; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

测试结果:


在这里插入图片描述
posted @ 2019-07-19 12:10  天涯海角路  阅读(114)  评论(0)    收藏  举报