dp1:分钱的问题
问题:
有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱(n <= 100000),有多少中组合可以组成n分钱?
网址:https://www.nowcoder.com/question/next?pid=18874168&qid=587672&tid=29129649
从题目来看是与华为的一道面试题相似,归属于简单的dp问题,首先定义dp[n],存放从0-n所需要的最小硬币数,v[i]存放硬币的面值,初始化dp[0] = 0,得出状态转移方程dp[i]=min{dp[i-1]+1,dp[i-v[j]] +1 };
对于状态方程可以这样来理解:给定了n分钱,设i为使用的币种数目,最后一个币种的面值为k,假设全使用k币,则k的数目为n/k,那么就有式子:
dp[i][n]=dp[i-1][n-0*k]+dp[i-1][n-1*k]+dp[i-1][n-2*k]+.......+dp[i-1][n-n/k*k];即所有情况包含:不使用k币,使用1张k币,使用2张k币.......全用k币,可以得到二位数组形式的状态转移方程;
简化为一维dp方程为:dp[i]=dp[i]+dp[i-v[j]];
代码:
import java.util.Scanner; public class Main { public static void main(String args[]) { Scanner input=new Scanner(System.in); int n=input.nextInt(); int coins[]= {1,2,5,10}; int [] dp=new int[100001]; dp[0]=1; for(int i=0;i<4;i++) { for(int j=coins[i];j<=n;j++) { dp[j]=(dp[j]+dp[j-coins[i]])%1000000007; } } System.out.println(dp[n]); } }
可以这样理解:对于每一个能够构成的总钱数,都可以像先前最开始二维数组推导的一样,使用1币1张,1币2张,2张1币,3张3币.......以此类推不停的迭代,钱j一直在增加,减去的币数也在不停的增加,下方的式子即为不停的迭代,减去
第1币,减去2币...后得到的方法数不停的迭代,即可得到所求的结果。
代码的时间复杂度仅为O(n),远小于暴力求解法;
dp[j]=(dp[j]+dp[j-coins[i]])%1000000007;
We Turn Not Older With Years ,But Newer Everyday!

浙公网安备 33010602011771号