如果单独购买其中一卷,那么可以打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 stub
count++;
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 stub
if(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) 无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。