编程之美之饮料供货

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

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

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

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

我们先把这个问题“数学化”一下吧。

假设STC共提供n种饮料,用(SiViCiHiBi)(对应的是饮料名字、容量、可能的最大数量、满意度、实际购买量)来表示第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;
}

如有错误,请指正,谢谢

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