首页 > 代码库 > 编程之美之饮料供货
编程之美之饮料供货
在微软亚洲研究院上班,大家早上来的第一件事是干啥呢?查看邮件?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),其中可能的最大数量指如果仅买某种饮料的最大可能数量。
分析:此题是一个典型的多重背包问题,把问题转化为背包模型就是:已知有n种物体,第i个物体共有Ci个,重量是Vi,价值是Hi,背包的总容量是W,求背包可装物体的最大价值。
动态转移方程:dp[i][j]表示第i个物体到最后一个物体可被选择,背包剩余容量为j,假设当前第i个物体取了k个放入背包(0<=k<=C[i]),则
dp[i][j] = max(dp[i+1][j-k*V[i]]+k*H[i]).其中,i从n-1开始到0结束,对每个i,j从1到W,则dp[0][W]即为最后的结果,具体代码如下:
#include<iostream> #include<memory.h> using namespace std; /** * W:饮料总容量的最大上限;N:饮料的种类;C:每种饮料的个数;H:每种饮料的满意度;V:每种饮料的容量 * 求:在满足最大容量<=W的前提下,如何购买饮料获得的满意度最大 */ int Cal(int W,int N,int* C,int* H,int* V) { if(W <=0 || N<=0 || C== NULL|| H==NULL || V==NULL)return 0; int i,j,k; int** dp = new int* [N+1]; for(i=0;i<=N;i++) { dp[i] = new int[W+1]; } memset(dp[N],0,sizeof(int)*(W+1)); for(i=N-1;i>=0;i--) { for(j=1;j<=W;j++) { dp[i][j] = 0; for(k=0;k<=C[i];k++) { if(j >= k*V[i]) { dp[i][j] = max(dp[i][j],dp[i+1][j-k*V[i]]+k*H[i]); } else break; } } } int res = dp[0][W]; for(i=0;i<=N;i++)delete[] dp[i]; delete[] dp; return res; } int main() { int w,n,i; while(cin >> w >> n) { int* C = new int[n]; int* H = new int[n]; int* V = new int[n]; for(i=0;i<n;i++)cin >> C[i] >> H[i] >> V[i]; cout << Cal(w,n,C,H,V)<< endl; delete[] C; delete[] H; delete[] V; } return 0; }
如有错误,请指正,谢谢