算法分析与设计——3.1 最少费用购物问题

问题描述:

    商店中每种商品都有标价。为了吸引顾客,商店提供了一组优惠商品价。优惠商品就是把一种或多种商品分成一组降价销售。

//算法设计
/* 
    设计算法计算出某一顾客所购商品应付的最少费用
*/
//数据输入
/*
文件input中提供预购商品数据
    第一行中有一个整数B(0<=B<=5),表示所购商品的种类数。
    在接下来的B行中,每行有三个数C(商品编码,1<=C<=999)K(购买该种商品的数1<=K<=5) P(商品正常单价,1<=P<=999).
    一次最多购买5x5=25件商品

文件offer中提供优惠组合
    第一行中有一个整数S(0<=S<=99),表示共有S种优惠组合。
    在接下来的S行中,每一行的第一个数据为商品优惠组合的商品的种类数。接下来就是数字对。每行最后一个数据是优惠价。
*/
//数据输出
/*
    输出应付的最少费用
*/
//算法思想
/*
    最优解就是:mincost=min(单价x数量,使用优惠的组合)
    递归表示:mincost=min(单价x数量,mincost(单价x数量,优惠后所需的商品数)+offer(优惠组合))

*/

struct Commodity
{
	int piece;//数量
	int price;//单价
};

static int MAXCODE = 999;//商品编码的最大值
static int SALECOMB = 99;//优惠商品组合数
static int MAXKIND = 5;     //商品种类
static int MAXQUANTITY = 5; //购买某种商品数量的最大值

 int B;//购买商品种类数
 int S;//当前优惠组合数
 int* num = new int[MAXCODE + 1];//记录商品编码与商品种类的对应关系
 int* product = new int[MAXKIND + 1];//记录不同种类商品的购买数量
 int** offer = new int*[SALECOMB + 1];// [MAXKIND + 1];//offer[i][j]: 商品组合的优惠价(j=0);某种优惠组合中某种商品需要购买的数量(j>0)
 Commodity* purch = new Commodity[MAXKIND + 1];//记录不同商品的购买数量和购买价格
 int mincost[6][6][6][6][6] = { 0 };//记录本次购买的总花费

void Initial()
{
	int i, j, n, p, t, C;
	num = new int[MAXCODE + 1];
	purch = new Commodity[MAXKIND + 1];
	product = new int[SALECOMB + 1];
	offer = new int *[SALECOMB + 1];
	for (int ii = 0; ii < SALECOMB + 1; ii++)
		offer[ii] = new int[SALECOMB + 1];
	//置0初始化
	for (i = 0; i < 100; i++)
		for (j = 0; j < 6; j++)
			offer[i][j] = 0;

	for (i = 0; i < 6; i++) {
		purch[i].piece = 0;
		purch[i].price = 0;
		product[i] = 0;
	}
	cout << "所购商品种类数:"<> B;
	for (i = 1; i <= B; i++) {
		cin>>C;
		cin >> purch[i].piece;
		cin >> purch[i].price;
		num[C] = i;//一个数组实现的哈希,目的是在O(1)的时间复杂度找到对用商品编码所在的数组下标
	}
	cout << "优惠组合数:"<> S;
	for (i = 1; i <= S; i++) {
		cin>>t;
		for (j = 1; j <= t; j++) {
			cin>>n;
			cin>>p;
			offer[i][num[n]] = p;
		}
		cin>>offer[i][0] ;
	}
}

/**
	*用于确定对于B种商品,给定每种商品的购买量,其最小花费
	*即确定子问题的最优解
	*/
void minicost()
{
	//已经购买1~5类商品的数量
	int i, j, k, m, n;
	//找到对应优惠后的花费
	int p;
	//最小花费
	int minm = 0;
	//将最小花费初始化为没有优惠策略时的花费
	for (i = 1; i <=B; i++)
		minm += product[i] * purch[i].price;

	//对s中优惠策略依次讨论
	for (p = 1; p <= S; p++) {
		i = product[1] - offer[p][1];//第一种商品扣除当前优惠组合后的剩余购买量(offer[i][j]: 商品组合的优惠价(j=0);某种优惠组合中某种商品需要购买的数量(j>0))
		j = product[2] - offer[p][2];
		k = product[3] - offer[p][3];
		m = product[4] - offer[p][4];
		n = product[5] - offer[p][5];
		//判断在当前优惠组合下,购买的商品总花费是否比没有优惠政策的花费少
		if (i >= 0 && j >= 0 && k >= 0 && m >= 0 && n >= 0 && mincost[i][j][k][m][n] + offer[p][0] < minm)
			//购买优惠组合前的花费+当前优惠组合花费
			minm = mincost[i][j][k][m][n] + offer[p][0];
	}
	//子问题最优组合花费
	mincost[product[1]][product[2]][product[3]][product[4]][product[5]] = minm;
}

void Traver(int i)
{
	//确定一个子问题,计算一次当前最小花费
	if (i > B) {
		minicost();
		return;
	}

	for (int j = 0; j <= purch[i].piece; j++) {//purch[i].piece表示第i类商品的最大数量
		product[i] = j;//记录第i类商品购买数量j的情况
		Traver(i + 1);//控制遍历所有的商品类
	}
}

时间复杂度

典型的以空间换取时间的做法。辅助空间O(n^5)。计算时间耗费取决于索要购买的商品的数量,时间复杂度是一个多项式时间。

你可能感兴趣的:(算法,c++,动态规划)