寫出 0-1 揹包問題的自底向上非遞歸的動態規劃算法。
輸入: 首先輸入 物品的 個數 n , 然後輸入 揹包的 容量 c , 再依次輸入每個 物品的
重量 wi , 最後依次輸入每個 物品的 價值 vi 。 注意: 所有值都不能隨機生成 ! ! !
輸出:物品的選擇向量。如:(1,0,0,1,1) 等。
示例:輸入:4 5 2 1 3 2 12 10 20 15 輸出:1 1 0 1 或(1,1,0,1 )
詳細解法:
package com.ccc;
import java.util.Scanner;
public class aaaaa {
/**
* @param args
*/
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(); //物品個數
int c=sc.nextInt();//揹包容量
int m[][]=new int[n+1][c+1];//最大價值
int v[]=new int[n+1];//記錄每個物品的價值
int w[]=new int[n+1];//記錄每個物品的重量
int x[]=new int[n+1];//記錄物品是否被放入揹包
for (int i = 1; i <=n; i++)//存入每個物品的重量
{
w[i]=sc.nextInt();
}
for (int i = 1; i <=n; i++)//存入每個物品的價值
{
v[i]=sc.nextInt();
}
pa(c, n, v, w, m);
out(n, c, x, w, m);
for (int i = 1; i <= n; i++)
{
System.out.print(x[i]+" ");
}
}
// 揹包問題的自底向上的算法
public static void pa(int c,int n,int v[],int w[],int m[][])
{
//---------------------------處理最後一行-----------------------------------
int jMax=Math.min(w[n]-1, c);// 這個用來避免一個物品的重量超大,導致揹包裝不下,例如第四個物品重量爲6,而揹包容量爲3,
//所以表圖中的最後一行應該全部爲0,這時jMax爲c,如果沒這個那麼用w[n]-1的話,那麼m可能越界了
for (int j = 0; j <=jMax; j++)
{
m[n][j]=0;//給最後一行的列數(即揹包容量)不到w[n]的賦值爲0,(價值爲0)
}
for (int j =w[n]; j <= c; j++)
{
m[n][j]=v[n];//當揹包的容量足夠容納w[n]時,將其價值賦值給他們
}
//-------------------------處理最後一行以上的-----------------------
for (int i = n-1; i>=1; i--)
{
jMax=Math.min(w[i]-1, c);
for (int j = 0; j <=jMax; j++)
{
m[i][j]=m[i+1][j];//當列數(即揹包容量)不到w[i]時,那麼將其下面那一行並且同列的這個值賦值給他,這個值可能爲0,可能已經有值
}
for (int j =w[i]; j <= c;j++)
{
m[i][j]=Math.max(m[i+1][j],m[i+1][j-w[i]]+v[i]);//如果當前的列數(即揹包容量)可以容納當前物品時,
//那麼看放入這個物品產生的最大價值大還是不放大,不放的話,那麼他的價值就是下行同列的價值,放入的話,即當前揹包容量減去當前這個物品所佔的揹包容量
//加上該物品的價值,看誰大,哪個價值大就選哪個,至於爲什麼是第i+1行,因爲你是放入物體B,看放入B後的剩餘的容量夠不夠放下物品A,A在i+1行
}
}
}
//算法的最優解
public static void out(int n,int c,int x[],int w[],int m[][])
{
for (int i = 1; i < n; i++)//<n是因爲下面是i和i+1比較
{
if(m[i][c]==m[i+1][c])//相等的話說明這個物品沒什麼用,沒用到
{
x[i]=0;
}
else //不相等的話說明這個物品用到了,即放到揹包裏了
{
x[i]=1;
c=c-w[i];//用到這個物品了,那麼減去這個物品代表的重量,看剩下的都是用到了誰(然後就是循環看)
}
}
x[n]=(m[n][c]==0?0:1);//因爲是最後一行,所以如果他不是0,代表就用到它了
}
}