01揹包
題目:有n個重量和價值分別爲wi,vi的物品,從這些物品中挑選出總重量不超過c的物品,求所以挑選方案中價值總和的最大。
1<=n<=100
1<=wi,vi<=100
1<=c<=10000
輸入:
n=4
(w,v)={(2,3),(1,2),(3,4),(2,2)}
c=5;
輸出:
7
//因爲這個問題只有選和不選兩種情況,所以叫做01揹包問題。
上一篇用的是遞推和記憶型遞歸求解,這一篇用dp動規來求解。
只要能分析出表格的每一步的來源,就能好的求解。
public class dp求解01揹包 {
static int[] w= {2,1,3,2};//重量表
static int[] v= {3,2,4,2};//價格表
static int n=4;//物品數量
static int c=5;//揹包的承重極限
public static void main(String[] args) {
System.out.println(dp());
}
private static int dp() {
int[][] dp=new int[n][c+1];
//初始化dp表的第一行
for (int i = 0; i < c+1; i++) {//i代表的是列
if (i>=w[0]) {//0號物品的容量
dp[0][i]=v[0];//第一行的每一列
}else {
dp[0][i]=0;
}
}
//其他行
for (int i = 1; i < n; i++) {
//j表示列,也是揹包的剩餘容量
for (int j = 0; j < c+1; j++) {
if (j>=w[i]) {//可以選(要得起)
int i1=v[i]+dp[i-1][j-w[i]];//選擇當前物品即i號物品
int i2=dp[i-1][j];//不選,就等於他的同列上一行
dp[i][j]=Math.max(i1, i2);
}else
dp[i][j]=dp[i-1][j];
}
}
return dp[n-1][c];
}
}
完全揹包
題目:有n種重量和價值分別爲wi,vi的物品,從這些物品中挑選出總重量不超過c的物品,求所以挑選方案中價值總和的最大。在這裏,每種物品可挑選任意多件。
1<=n<=100
1<=wi,vi<=100
1<=c<=10000
輸入:
n=3
(w,v)={(3,4),(4,5),(2,3)}
c=7;
輸出:
10(0號物品選一個,二號物品選兩個)
代碼:
import java.util.Scanner;
public class W完全揹包 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[] w=new int[n];
int[] v=new int[n];
for (int i = 0; i < n; i++) {
w[i]=sc.nextInt();
}
for (int i = 0; i < n; i++) {
v[i]=sc.nextInt();
}
int c=sc.nextInt();
System.out.println(dp(n,c,w,v));
}
public static int dp(int n,int c,int[] w,int[] v){
int[][] dp=new int[n][c+1];
//第一行初始化,我們可以拿取當前物品多少個,那麼就可以加上這個物品的多少倍的價值
for (int i = 0; i <=c ; i++) {
dp[0][i]=i/w[0]*v[0];
}
for (int i = 1; i < n; i++) {
for (int j = 0; j <= c; j++) {
for (int k = 0; k*w[i] <= j ; k++) {
dp[i][j]=Math.max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
}
}
}
return dp[n-1][c];
}
}