动态规划 堆沙子问题

堆沙子问题:

        设有n堆沙子排成一排,其编号为1,2,3,…,n(n≤100)。每堆沙子有一定的数量,如下表
        13 7 8 16 21 4 18
        现在要将n堆沙子归并成一堆。归并的过程为每次只能将相邻的两堆沙子堆成一堆,这样经过n-1次归并之后最后成为一堆,如上面7堆沙子,可以有多种方法归并成一堆,归并的代价是这样定义的,将两堆沙子归并为一堆时,两堆沙子数量的和称为归并2堆沙子的代价。由此可见,不同归并过程得到的总的归并代价是不一样的。
        问题:n堆沙子的数量给出之后,找出一种合理的归并方法,使总的归并代价为最小。

分析思路:

        堆沙子问题只能是相邻的两堆沙子,因为这个条件,让堆沙子的过程有规律可循,问题就可以转化为如果得到两堆沙子的过程,依次往下,用f(n,m)来表示最初沙子从第n到第m合并后的值,g(n,m)表示从第n堆到第m堆的总和。我们做个简单的推演。

        f(1,2)=13+7=20   f(2,3)=7+8=15

        f(1,3)=f(1,2)+28=f(1,2)+g(1,3)=48

        f(1,3)=f(2,3)+28=f(2,3)+g(1,3)=43

        当三个合并成一个的时候就有了两种选择,先合并1,2然后3,先合并2,3然后再合并1。

        f(1,4)=f(1,2)+f(3,4)+g(1,4)

        f(1,4)=f(1,3)+g(1,4)

        f(1,4)=f(2,4)+g(1,4)

        f(n,m)是由两部分组成,一部分是两个沙堆的代价和,另一部分就是g(n,m),g(n,m)在具体的的n,m下就是定值,如果想让总代价最小,就需要两个沙堆的代价和最小。

        合并情况其实也是可以找到规律的

        f(n,m)=f(n,m-1)+g(n,m)

        f(n,m)=f(n+1,m)+g(n,m)

        f(n,m)=f(n,n+x)+f(n+x+1,m)+g(n,m)

        其实合并只有这两种情况,合并好的加没有合并过的,两个合并过的相加。假如f(n,m)=f(n,n+x)+f(n+x+1,m)+g(n,m) 是f(n,m)的最小值,那么我们只要保证f(n,n+x),f(n+x+1,m)都是最小值就可以。然后依次往下找组成的最小值。但是想找最小值就必须从底层开始计算,一层一层的计算。因为不知道高层的最小情况,所以必须保证从高层计算的所有结果。但是比所有结果都算出来找最小,这种算法计算的量还是比较小的。他需要从顶向下分析,从下向上计算。

        能用动态规划的情况一般都是顶层结果依赖底层结果,他们直接的是一种包含关系,但是分治法分开的小组计算的结果没有任何影响。这也是两种算法的区别。

代码实现:

public static void sand() {
		int[] weight = { 0, 13, 7, 8,16,21,4,18};
        //用一个二维数组来存储中间需要的结果
		int[][] sumData = new int[weight.length][weight.length];
        //len用来控制层数计算
		int len = 1;
		while (len < weight.length-1) {
			for (int i = 1; i < (weight.length - len); i++) {
                //计算最小值的过程
				int j = i + len;
				int min = sumData[i + 1][j];
				int k = i + 1;
				while (k < j) {
					int score = sumData[i][k] + sumData[k + 1][j];
					if (min > score)
						min = score;
					k++;
				}
				sumData[i][j] = min + sum(weight, i, j);
			}
			len++;
		}
		System.out.println(sumData[1][weight.length-1]);
	}

        

        

        

        

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值