动态规划:买书问题

来源:互联网 发布:电视机顶盒软件 编辑:程序博客网 时间:2024/05/16 19:49
有一书店引进了一套书,共有3卷,每卷书定价是100元,书店为了搞促销,推出一个活动,活动如下:
       如果单独购买其中一卷,那么可以打9.5折。
       如果同时购买两卷不同的,那么可以打9折。
       如果同时购买三卷不同的,那么可以打8.5折。

       如果小明希望购买第1卷x本,第2卷y本,第3卷z本,那么至少需要多少钱呢?(x、y、z为三个已知整数)。

首先三卷书的价格一样,因此三卷书可以无差别对待,比如买3本第一卷,2本第二卷和1本第三卷,和买1本第一卷,2本第二卷,三本第三卷属于同一种情况。

1.一次买书过程可以买三本、两本或一本。而每经过一次选择,剩下的问题又变成给定一定数量的书,求花钱最少的方案。即原问题可以分解为若干子问题。

2.状态转移方程

设F(x,y,z)为当购买x本一卷,y本二卷,z本三卷时的最小花费。假定x>=y>=z

F(x,y,z)=0(x=y=z=0)

F(x,y,z)=min{

F(x-1,y-1,z-1)+3*100*0.85,    (z>=1,购买三卷各一本)

F(x-1,y-1,z)+2*100*0.9,             (y>=1,购买两卷)

F(x-1,y,z)+100*0.95  (x>=1,,购买一卷)

}

实现代码如下:

public class BuyBook {static int Max=100000;static int count=0;static int MinMoney[][][]=new int[100][100][100];public static void main(String [] args){int x = 2,y = 5,z = 8;System.out.println(minMoney(x,y,z));System.out.println("调用minMoney函数的次数"+count);}private static int minMoney(int x, int y, int z) {// TODO Auto-generated method stubcount++;int [] num={x,y,z};Arrays.sort(num);x=num[2];y=num[1];z=num[0];System.out.println("x:"+x+"  y:"+y+"  z:"+z);if(MinMoney[x][y][z]!=0)return MinMoney[x][y][z];if(x==0)return 0;else if(z>=1){MinMoney[x][y][z]= min(minMoney(x-1,y-1,z-1)+255,minMoney(x-1,y-1,z)+180,minMoney(x-1,y,z)+95);}else if(y>=1){MinMoney[x][y][z]= min(Max,minMoney(x-1,y-1,z)+180,minMoney(x-1,y,z)+95);}else if(x>=1){MinMoney[x][y][z]= min(Max,Max,minMoney(x-1,y,z)+95);}return MinMoney[x][y][z];}private static int min(int i, int j, int k) {// TODO Auto-generated method stubif(i<=j&&i<=k)return i;else return j<k?j:k;}}

以下总结参考自博客点击打开链接

接下来,我们就进行一下总结:

    递归到动规的一般转化方法

    递归函数有n个参数,就定义一个n维的数组,数组的下标是递归函数参数的取值范围,数组元素的值是递归函数的返回值,这样就可以从边界值开始, 逐步填充数组,相当于计算递归函数值的逆过程。

    动规解题的一般思路

    1. 将原问题分解为子问题

  •     把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。子问题都解决,原问题即解决(数字三角形例)。
  •     子问题的解一旦求出就会被保存,所以每个子问题只需求 解一次。

    2.确定状态

  •     在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
  •     所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。 在数字三角形的例子里,一共有N×(N+1)/2个数字,所以这个问题的状态空间里一共就有N×(N+1)/2个状态。

    整个问题的时间复杂度是状态数目乘以计算每个状态所需时间。在数字三角形里每个“状态”只需要经过一次,且在每个状态上作计算所花的时间都是和N无关的常数。

    3.确定一些初始状态(边界状态)的值

    4. 确定状态转移方程

     定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。

    能用动规解决的问题的特点

    1) 问题具有最优子结构性质。如果问题的最优解所包含的 子问题的解也是最优的,我们就称该问题具有最优子结 构性质。

    2) 无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。



原创粉丝点击