饮料供货

1. 问题以及扩展

    本题所说的问题是微软每天为员工提供各种不同的饮料,如可乐,酸奶,豆浆,咖啡,绿茶……..(待遇不错啊,呵呵),饮料i的单位容量为Vi,其中每种饮料单个容量都是2的方幂,员工对饮料i的满意度为Hi,冰柜的总容量为V(每天必须装满),问题是如何组合现有的各种饮料,使总的满意度最高。

    已知每种饮料的名字、容量、数量以及满意度,求总容量V一定的情况下的最大满意度。

    扩展:
        (1) 如何度量每一种饮料的满意度,简单的平均,则不一定使得所有人的满意度之和达到最高!
        (2) 每个人都有一个满意度量,则这时候如何计算总的最大满意度?

    注:遗憾的是自己提出的扩展问题却解决不了,期待高人指点。

2. 数据的产生

    针对该问题,随机生成了100种产品,实现代码如下所示:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <fstream>
using namespace std;
#define MAXNUM 5

void generData()
{
	ofstream outfile("Data.txt");
	int drinkID = 0;
	int volumn = 0;
	int quantity = 0;
	float satisfaction = 0.0;
	srand((unsigned)time(NULL));
	for (drinkID=0; drinkID<100; drinkID++)
	{
		volumn = pow(2, rand()%7);
		quantity = rand()%10+1;
		satisfaction = 1.0/(1 + rand()%20);
		outfile<<drinkID<<" "<<volumn<<" "<<quantity<<" "<<satisfaction<<endl;
	}
	outfile.close();
}

int main(void)
{
	generData();
	return 1;
}

3. 求解

    3.1 动态规划

    最优化公式:

Opt(v',i) = max{max{k*Hi + Opt(v'-vi*k, i-1)}, Opt(v', i-1)}
    其中v'表示容量,k表示购买第i种饮料的数量,Hi是第i种饮料的满意度。初始条件:Opt(j, 0) = 0表示任何容量j选择0种饮料时满意度均为零。Opt(v, n)为最终求解的结果。

    实现代码如下:

#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

#define DRINKKINS 100
#define TOTALVOLUMN 14

class drink
{
public:
	int id;
	int volumn;
	int count;
	float satisfaction;

	drink()
	{
		
	}
	drink(int newid, int newvolumn, int newcount, float newsatisfaction)
	{
		id = newid;
		volumn = newvolumn;
		count = newcount;
		satisfaction = newsatisfaction;
	}
	~drink()
	{
		
	}
	inline void set(int newid, int newvolumn, int newcount, float newsatisfaction)
	{
		id = newid;
		volumn = newvolumn;
		count = newcount;
		satisfaction = newsatisfaction;
	}
	void outdrink()
	{
		cout<<id<<" "<<volumn<<" "<<count<<" "<<satisfaction<<endl;
	}
};

void cal (float Optimal[DRINKKINS+1][TOTALVOLUMN+1], drink drinks[DRINKKINS+1])
{
	for (int i=0; i<=TOTALVOLUMN; ++i)
	{
		Optimal[0][i] = 0;
	}
	for (int i=1; i<= DRINKKINS; i++)
	{
		for (int j=0; j<=TOTALVOLUMN; ++j)
		{
			Optimal[i][j] = Optimal[i-1][j];//初始值
			for (int k=1; k<=drinks[i].count && j>= k*drinks[i].volumn; ++k)
			{	
				float tempOpt = k*drinks[i].satisfaction + Optimal[i-1][j-k*drinks[i].count];
				Optimal[i][j] = Optimal[i][j]>tempOpt ? Optimal[i][j]:tempOpt;
			}
		}
	}
}

int main()
{
	ifstream fin("Data.txt");//Data.txt为存储数据的文件
	char s1[10], s2[10], s3[10], s4[10];
	drink drinks[DRINKKINS+1];
	int i = 1;
	while (fin>>s1, fin>>s2, fin>>s3, fin>>s4)
	{
		drinks[i++].set(atoi(s1), atoi(s2), atoi(s3), atof(s4));
	}
	fin.close();

	//注意矩阵第一行的数据均应为零,表示虽然容量有,但是第0种饮料是不存在的,只是虚拟方便计算
	float Optimal[DRINKKINS+1][TOTALVOLUMN+1];
	cal(Optimal, drinks);
	cout<<"The Maxmum satisfaction is :"<<Optimal[DRINKKINS][TOTALVOLUMN]<<endl;

	return 1;
}
    3.2 贪心
     基于容量的贪心实现比较麻烦,例如总容量V=7=1+2+4,显然我们可以选择容量分别为1,2,4中满意度最高的。但4=2+2,即我们可以选择容量分别为1,2,2,2的饮料从而获得更高的满意度,当然我们可以将4=2+2也当作容量为4的进行贪心,可是我们无法确定我们选择此方案时是否构成该满意度的两种(或一种)饮料是否还有这么多容量。
    个人理解:贪心是为了简化问题的求解,显然这时候用谈心会增大问题的求解难度,认为不好!不知道是否存在高效的实现方法?思考中……
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值