编程之美:第一章 1.4 买书问题

/*
买书问题:

过程:
接受输入,对输入按照从大到小排序(a,b,c,d,e),然后选取min,设置递归出口是全0


输入:
2 1 1 1 1
2 2 2 1 1
2 2 2 2 2
10 10 10 10 10
输出:
38.0
51.2
60.0
300.0
*/

/*
关键:
1 int _iCostArr[MAXSIZE][MAXSIZE][MAXSIZE][MAXSIZE][MAXSIZE];//用作记忆化搜索,原来可以设置5维数组
2 void my_sort(int& a,int& b,int& c,int& d,int& e)//注意这些值返回后继续用的,所以要用引用
  a = _iSortArr[0];//注意再重新返回a,因此形参要用引用
3  my_sort(a,b,c,d,e);//按照从大到小排序
 int& iRet = _iCostArr[a][b][c][d][e];//注意,这里使用引用,可以提高速度,并且会用iRes为cost赋值
 if(iRet != -1)//记忆化搜索,如果已经求解过,就直接返回,避免重复递归
 {
  return iRet;
4 if(a >= 1 && b < 1)//如果只剩下一个种类的书了,那么最大值自然就是,没有优惠,自己付钱
5  else if(a >= 1 && e >= 1)//a,b,c,d,e均有剩余,可以享受7.5折
 {
  return iRet =  min(5*8*75 + buyBook(a-1,b-1,c-1,d-1,e-1), 4*8*80 + buyBook(a-1,b-1,c-1,d-1,e) ,
   3*8*90 + buyBook(a-1,b-1,c-1,d,e),2*8*95 + buyBook(a-1,b-1,c,d,e) ,
   800 + buyBook(a-1,b,c,d,e));
*/

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <assert.h>
using namespace std;

const int MAXSIZE = 15;
int _iCostArr[MAXSIZE][MAXSIZE][MAXSIZE][MAXSIZE][MAXSIZE];//用作记忆化搜索,原来可以设置5维数组
int _iSortArr[5];

bool compare(int a,int b)
{
 return a > b;
}

void my_sort(int& a,int& b,int& c,int& d,int& e)//注意这些值返回后继续用的,所以要用引用
{
 _iSortArr[0] = a;
 _iSortArr[1] = b;
 _iSortArr[2] = c;
 _iSortArr[3] = d;
 _iSortArr[4] = e;
 sort(_iSortArr,_iSortArr+5,compare);
 a = _iSortArr[0];//注意再重新返回a,因此形参要用引用
 b = _iSortArr[1];
 c = _iSortArr[2];
 d = _iSortArr[3];
 e = _iSortArr[4];
}

int min(int a,int b)
{
 return a < b ? a : b;
}

int min(int a,int b,int c)
{
 return min( min(a,b),c);
}

int min(int a,int b,int c,int d)
{
 return min(min(a,b),min(c,d));
}

int min(int a,int b,int c,int d,int e)
{
 return min( e,min( min(a,b) , min(c,d) ) );
}

int buyBook(int a,int b,int c,int d,int e)
{
 assert(a >= 0 && b >= 0 && c >= 0 && d >= 0 && e >=0);
 if(!a &&  !b && !c && !d && !e)//递归出口,如果每本书都是0本,那么最少的价钱自然是0
 {
  return 0;
 }
 my_sort(a,b,c,d,e);//按照从大到小排序
 int& iRet = _iCostArr[a][b][c][d][e];//注意,这里使用引用,可以提高速度,并且会用iRes为cost赋值
 if(iRet != -1)//记忆化搜索,如果已经求解过,就直接返回,避免重复递归
 {
  return iRet;
 }
 //我们应该从最大的开始算,要不然就不好求最小值了
 if(a >= 1 && b < 1)//如果只剩下一个种类的书了,那么最大值自然就是,没有优惠,自己付钱
 {
  return iRet = (800 + buyBook(a-1,b,c,d,e));
 }
 else if(a >= 1 && b >= 1 && c < 1)//如果a与b均剩余,其余三类书空了,可以享受95折
 {
  return iRet =  min( 2*8*95 + buyBook(a-1,b-1,c,d,e) , 800 + buyBook(a-1,b,c,d,e));
 }
 else if(a >= 1 && c >= 1 && d < 1)//如果a,b,c均有剩余,可享受9折
 {
  return iRet =  min( 3*8*90 + buyBook(a-1,b-1,c-1,d,e), 2*8*95 + buyBook(a-1,b-1,c,d,e) ,
   800 + buyBook(a-1,b,c,d,e) );
 }
 else if(a >= 1 && d >= 1 && e < 1)//a,b,c,d,均剩余,可享受8折
 {
  return iRet =  min( 4*8*80 + buyBook(a-1,b-1,c-1,d-1,e) , 3*8*90 + buyBook(a-1,b-1,c-1,d,e),
   2*8*95 + buyBook(a-1,b-1,c,d,e) , 800 + buyBook(a-1,b,c,d,e));
 }
 else if(a >= 1 && e >= 1)//a,b,c,d,e均有剩余,可以享受7.5折
 {
  return iRet =  min(5*8*75 + buyBook(a-1,b-1,c-1,d-1,e-1), 4*8*80 + buyBook(a-1,b-1,c-1,d-1,e) ,
   3*8*90 + buyBook(a-1,b-1,c-1,d,e),2*8*95 + buyBook(a-1,b-1,c,d,e) , 
   800 + buyBook(a-1,b,c,d,e));
 }
 else
 {
 }
}

int butBook_memory(int a,int b,int c,int d,int e)//记忆化搜索,说白了就是剪枝,可以避免递归的效率降下
{
 assert(a >= 0 && b >= 0 && c >= 0 && d >= 0 && e >=0);
 if(!a &&  !b && !c && !d && !e)//递归出口,如果每本书都是0本,那么最少的价钱自然是0
 {
  return 0;
 }
}

void process()
{
 int i = 0;
 while(EOF != scanf("%d %d %d %d %d",&_iSortArr[i],&_iSortArr[i+1],&_iSortArr[i+2],
  &_iSortArr[i+3],&_iSortArr[i+4]))
 {
  memset(_iCostArr,-1,sizeof(_iCostArr));
  int iRes = buyBook(_iSortArr[i],_iSortArr[i+1],_iSortArr[i+2],
   _iSortArr[i+3],_iSortArr[i+4]);
  printf("%.1f\n",iRes*1.0/100.0);
 }
}

int main(int argc,char* argv[])
{
 process();
 getchar();
 return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值