zoukankan      html  css  js  c++  java
  • 动态规划【思想】求解凑硬币问题

    问题描述

    假设有 1 元,3 元,5 元的硬币若干(无限),现在需要凑出 11 元,问如何组合才能使硬币的数量最少?

    问题分析

    乍看之下,我们简单的运用一下心算就能解出需要 2 个 5 元和 1 个 1 元的解。当然这里只是列出了这个问题比较简单的情况。当硬币的币制或者种类变化,并且需要凑出的总价值变大时,就很难靠简单的计算得出结论了。贪心算法可以在一定的程度上得出较优解,但不是每次都能得出最优解。

    这里我们打算采用动态规划思路来解决该问题,一步一步来:

    我们先假设一个函数 d(i) 来表示需要凑出 i 的总价值需要的最少硬币数量。

    1. 当 i = 0 时,很显然我们可以知道 d(0) = 0。因为不要凑钱了嘛,当然也不需要任何硬币了。注意这是很重要的一步,其后所有的结果都从这一步延伸开来
    2. 当 i = 1 时,因为我们有 1 元的硬币,所以直接在第 1 步的基础上,加上 1 个 1 元硬币,得出 d(1) = 1
    3. 当 i = 2 时,因为我们并没有 2 元的硬币,所以只能拿 1 元的硬币来凑。在第 2 步的基础上,加上 1 个 1 元硬币,得出 d(2) = 2
    4. 当 i = 3 时,我们可以在第 3 步的基础上加上 1 个 1 元硬币,得到 3 这个结果。但其实我们有 3 元硬币,所以这一步的最优结果不是建立在第 3 步的结果上得来的,而是应该建立在第 1 步上,加上 1 个 3 元硬币,得到 d(3) = 1
    5. ...

    接着就不再举例了,我们来分析一下。可以看出,除了第 1 步这个看似基本的公理外,其他往后的结果都是建立在它之前得到的某一步的最优解上,加上 1 个硬币得到。我们可以得出下面的公式:

    d(i)=d(j)+1

    这里的j必须要小于等于i!

    通俗的讲就是凑齐到i的话,只需要在凑齐j前提下再加一枚硬币就行了,具体怎么做呢?

    那这里我们加上的是哪个硬币呢。嗯,其实很简单,把每个硬币试一下就行了:

    1. 假设最后加上的是 1 元硬币,那 d(i) = d(j) + 1 = d(i - 1) + 1
    2. 假设最后加上的是 3 元硬币,那 d(i) = d(j) + 1 = d(i - 3) + 1
    3. 假设最后加上的是 5 元硬币,那 d(i) = d(j) + 1 = d(i - 5) + 1

    我们分别计算出 d(i - 1) + 1d(i - 3) + 1d(i - 5) + 1 的值,取其中的最小值,即为最优解,也就是 d(i)

    之所以我们要对i进行-1 -3 -5操作,是因为减去num(某个数,例如3),得到的就是加上3硬币之前的那个数(j,j=i-3),凑齐该数需要的硬币数目,再加上3元的硬币,得到了需要的硬币数,再取得最小的硬币数目,作为要凑齐某数需要的硬币数目!

    public class CoinProblemBasicTest {
    	private static int[] d; // 储存结果
    	private static int[] coins = { 1, 3, 5 }; // 硬币种类
    
    	public static void main(String[] args) {
    		int sum = 11; // 需要凑 11 元
    		d = new int[sum + 1]; // 初始化数组
    
    		d_func(0, sum); // 计算需要凑出 0 ~ sum 元需要的硬币数量
    		for (int i = 0; i <= sum; i++) {
    			System.out.println("凑齐 " + i + " 元需要 " + d[i] + " 个硬币");
    		}
    	}
    
    	private static void d_func(int i, int num) {
    		// 如果i==0,直接计算下一个
    		if (i == 0) {
    			d[i] = 0;
    			d_func(i + 1, num);
    		} else {
    			// 如果i不为0
    			int min = 999;
    			for (int coin : coins) {
    				if (i >= coin && (d[i - coin] + 1) < min) {
    					min = d[i - coin] + 1;
    				}
    			}
    			d[i] = min;
    
    		}
    		if (i < num) {
    			d_func(i + 1, num);
    		}
    	}
    }
    

      

                    

  • 相关阅读:
    selenium+python环境搭建
    TCP/IP 常用协议
    爬虫之scrapy高级部分等相关内容-138
    爬虫之xpath和scrapy的基础使用等相关内容-137
    爬虫之打码平台(超级鹰)破解验证码等相关内容-136
    爬虫之bs4文档树和selenium的基础使用等相关内容-135
    RBAC、xadmin、django缓存、django信号等相关内容-91
    django-restframework-jwt多方式登录、自定义user表及签发token、book表单增删查改等相关内容-90
    爬虫之bs4模块的基础使用等相关内容-134
    django-restframework-jwt认证基础使用等相关内容-89
  • 原文地址:https://www.cnblogs.com/Booker808-java/p/8894359.html
Copyright © 2011-2022 走看看