揹包問題html
在n個物品中挑選若干物品裝入揹包,最多能裝多滿?假設揹包的大小爲m,每一個物品的大小爲A[i]java
樣例函數
若是有4個物品[2, 3, 5, 7]spa
若是揹包的大小爲11,能夠選擇[2, 3, 5]裝入揹包,最多能夠裝滿10的空間。code
若是揹包的大小爲12,能夠選擇[2, 3, 7]裝入揹包,最多能夠裝滿12的空間。htm
函數須要返回最多能裝滿的空間大小。blog
解題get
動態規劃it
這是最基礎的揹包問題,特色是:每種物品僅有一件,能夠選擇放或不放。io
用子問題定義狀態:即f[i][j]前i個物品放入大小爲j的空間裏可以佔用的最大致積。
則其狀態轉移方程即是:
f[i][j]=max{f[i-1][j],f[i-1][j-A[i]]+A[i]}
不放第i個物品:f[i-1][j]
放第i個物品:那麼問題就轉化爲「前i-1件物品放入剩下的容量爲j-A[i]的揹包中」,此時能得到的最大致積就是f[i-1][j-A[i]]再加上經過放入第i件物品得到的體積A[i]
注意上面的狀態轉移方程i的下標是從1開始的,下面程序是從0開始的,要適當調整
public class Solution { /** * @param m: An integer m denotes the size of a backpack * @param A: Given n items with size A[i] * @return: The maximum size */ public int backPack(int m, int[] A) { // write your code here int[][] P = new int[A.length+1][m+1]; for(int i = 1;i<= A.length; i++){ for(int j = m;j>=0;j--){ if(j>=A[i-1]){ P[i][j] = P[i-1][j-A[i-1]] + A[i-1]; } P[i][j] = Math.max(P[i][j],P[i-1][j]); } } return P[A.length][m]; } }
或者對0的時候單獨考慮
public class Solution { /** * @param m: An integer m denotes the size of a backpack * @param A: Given n items with size A[i] * @return: The maximum size */ public int backPack(int m, int[] A) { // write your code here int[][] P = new int[A.length][m+1]; for(int i = 0;i< A.length; i++){ for(int j = m;j>=0;j--){ if(i==0){ // 第0個物品能夠放入空間爲j的揹包中,直接放入 if(j>=A[i]) P[i][j] = P[i][j-A[i]] + A[i]; }else{ if(j>=A[i]){ P[i][j] = P[i-1][j-A[i]] + A[i]; } P[i][j] = Math.max(P[i][j],P[i-1][j]); } } } return P[A.length-1][m]; } }
上面的時間空間複雜度都是O(MN)
狀態轉移方程式:
f[i][j] = Max(f[i-1][j],f[i-1][j-A[i]]+A[i])
f[i][j]表示對前i個物品,j的空間所可以取得的最大價值
實際上,咱們須要求的是對全部的n個商品在m的空間中可以放入的最大價值
能夠修改定義一個一維矩陣,長度就是m的空間的價值
f[j] = Max(f[j],f[j-A[i]]+A[i]) 這裏就至關於對上面的矩陣進行了壓縮
public class Solution { /** * @param m: An integer m denotes the size of a backpack * @param A: Given n items with size A[i] * @return: The maximum size */ public int backPack(int m, int[] A) { // write your code here int[] P = new int[m+1]; for(int i=0;i<A.length;i++){ for(int j=m;j>=0;j--){ if(j>=A[i]) P[j] = Math.max(P[j],P[j-A[i]] + A[i]); } } return P[m]; } }
參考:http://love-oriented.com/pack/P01.html
能夠輸出零錢的具體方案
package org.oj.dp; import java.util.ArrayList; import java.util.Arrays; public class 換零錢問題 { static ArrayList<ArrayList<String>> lists; public static void main(String[] args) { // TODO Auto-generated method stub int[] A = {1,2,5,10,20,50}; lists = new ArrayList<ArrayList<String>>(11); ArrayList<String> l1 = new ArrayList<String>(); l1.add(""); lists.add(l1); for(int i=0;i<11;i++){ lists.add(new ArrayList<String>(10)); } changeMoney(A,10); System.out.println(lists); } /** * 根據上一個零錢方案,更新當前零錢方案 * @param A * @param money */ private static void changeMoney(int[]A,int money){ int[] dp = new int[money+1]; dp[0] = 1; for(int i=0;i<A.length;i++){ for(int j=A[i];j<=money;j++){ dp[j] +=dp[j-A[i]]; // 記錄零錢方案 for(int k=0;k<lists.get(j-A[i]).size();k++){ lists.get(j).add(lists.get(j-A[i]).get(k)+" "+A[i]); } } } System.out.println(Arrays.toString(dp)); } /** * DFS實現 * @param m * @param A * @param start * @param result * @param str */ private static void DFS(int m,int[]A,int start,ArrayList<String>result,String str){ if(m == 0){ result.add(str); return; } if(A[start]> m){ return; } for(int i = start;i<A.length;i++){ DFS(m - A[i],A,i,result,str+ " "+A[i]); } } }