编程之美_买书问题

       对于买的不同的书越多,打的折扣也就越大,由此想到可用贪心算法,将每一组尽可能多的包含不同的书,这样的折扣就越大,花的钱就越少。然而,在这里贪心算法却出现了反例,当买8本书时,分组为5+3的贪心算法却不如分组为4+4的算法花的钱少:5+3: 5*8*0.75 + 3*8*0.9 = 51.6,   4+4: 2 * 4*8*0.8 = 51.2。这是因为买三本不同的书的折扣为10%,而买4本不同的书的折扣为20%,两者之间的折扣相差太大,导致出现了反例。因此要对贪心算法做出调整,即在n本先按正常的贪心算法分组,然后将所有5 + 3 的分组对改成4+4的分组对(例如买(7,6,5,3,2)的书分组为5+5+4+3+3+2+1的组合,应该调整为4+4+4+4+4+2+1。)

      如果要买的书为(Y1,Y2,Y3,Y4,Y5) 而且满足Y1>=Y2>=Y3>=Y4>=Y5(如果不满足可以调整到满足)贪心策略建议买书的分组为买Y5组且每组含有5种不同书(1,1,1,1,1),买Y4-Y5组且每组含有4种不同的书(1,1,1,1,0),买Y3-Y4组且每组含有3种不同书(1,1,1,0,0),买Y2-Y1组且每组含有2中不同的书(1,1,0,0,0),买Y1-Y2组且每组含有1中不同的书(1,0,0,0,0)。调整过程为:要把买5种不同书的组和买3种不同书的组调整为两组买4种不同书,这种组合共有K对,K=min(Y5, Y3-Y4); 调整后  买5种不同的书有Y5-K组,买4种不同的书有Y4-Y5+2*K组,买3种不同的书有Y3-Y4-K组,买2种不同的书有Y2-Y3组,买1种不同的书有Y1-Y2组。代码:

#include <iostream>
#include <algorithm>

using namespace std;

const double Price = 8;
const double Discounts[5] = {1, 0.95, 0.9, 0.8, 0.75};
const int Book_kind = 5;

int comp(int a, int b)
{
	return a > b;
}

int min(int a, int b)
{
	if(a > b)
		return b;
	else
		return a;
}

double BuyBook(int *books)
{
	sort(books,books+Book_kind, comp);

	int g[5];  //存放不同的分组数,i+1代表i+1种不同的书(0<= i <= 4)
	g[0] = books[0] - books[1];  //买1种不同的书对应的组数
	g[1] = books[1] - books[2];  //买2种不同的书对应的组数
	g[2] = books[2] - books[3];  //买3种不同的书对应的组数
	g[3] = books[3] - books[4];  //买4种不同的书对应的组数
	g[4] = books[4];             //买5种不同的书对应的组数

	int k = min(g[2], g[4]);

	/*
	 *  针对有贪心算法有反例,所以要调整贪心算法
	 *  在5+3的情况时要改成4+4
	*/
	if(k > 0)    
	{
		g[2] -= k;
		g[4] -= k;
		g[3] += 2*k;
	}

	double sum = 0;
	for(int i = 0; i < Book_kind; i++)
	{
		sum += g[i] * (i + 1) * Price * Discounts[i];  //组数*每组书的个数*单价*折扣
	}

	return sum;
}


int main()
{
	int book[Book_kind];
	for(int i = 0; i < Book_kind; i++)
	{
		cin>>book[i];
	}

	double sum = BuyBook(book);

	cout<<sum<<endl;

	return 0;
}


 对于解法二使用动态规划法,书上给的解法调用了大量的递归,时间复杂度为O(Y1*Y2*Y3*Y4*Y5),但是我运行了要7、8分钟才能出结果,不知到是代码没写好,还是本身这个算法有问题,个人认为是这个算法相对太复杂了,导致的运行时间较长。先保存代买,以后有更好的理解了再来改:

#if 1
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int price = 8;
const int book_kind = 5;
const double discount[] = {1, 0.95, 0.9, 0.8, 0.75};

bool comp(int a, int b)
{
	return a > b;
}
double Mincost(vector<int> vec)
{
	/*
	* 在每次调用函数时,要先对容器内的元素排序,按降序排列,使之进行判断
	*/
	sort(vec.begin(), vec.end(), comp);

	vector<int> temp(vec);

	bool isZero = true;
	for(int i=0; i < book_kind; i++)
	{
		if(temp[i] != 0)
		{
			isZero = false;
			break;
		}
	}
	if(isZero)
		return 0;

	double min = 100000.0, sum;

	if(vec[4] >= 1)
	{
		temp = vec;
		temp[4] -= 1;
		temp[3] -= 1;
		temp[2] -= 1;
		temp[1] -= 1;
		temp[0] -= 1;
		sum = 5 * price * discount[4] + Mincost(temp);

		if(sum < min)
			min =sum;
	}

	if(vec[3] >= 1)
	{
		temp = vec;
		temp[3] -= 1;
		temp[2] -= 1;
		temp[1] -= 1;
		temp[0] -= 1;

		sum = 4 * price * discount[3] + Mincost(temp);
		if(sum < min)
			min = sum;
	}

	if(vec[2] >= 1)
	{
		temp = vec;
		temp[2] -= 1;
		temp[1] -= 1;
		temp[0] -= 1;

		sum = 3 * price * discount[2] + Mincost(temp);
		if(sum < min)
			min = sum;
	}

	if(vec[1] >= 1)
	{
		temp = vec;
		temp[1] -= 1;
		temp[0] -= 1;

		sum = 2 * price * discount[1] + Mincost(temp);
		if(sum < min)
			min = sum;
	}

	if(vec[0] >= 1)
	{
		temp = vec;
		temp[0] -= 1;

		sum = 1 * price * discount[0] + Mincost(temp);
		if(sum < min)
			min = sum;
	}

	return min;
}

int main()
{
	int book[book_kind] = {7,6,5,3,2};
	vector<int> vec(book, book+book_kind);

	double result = Mincost(vec);

	cout<<result<<endl;

	return 0;
}

#endif


 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值