問題の説明:
バックパックの総容量はVである、N項目は、重量のクラスIの記事[i]は、値の値[I]で、そこにされている
その後、バックパックに行くどのような手段で、最終的なパッケージ商品合計ことに、ロードされました最大値。ここで及び設置方法は、主に三つの項目からなる:
1,0-1バックパック:商品の各カテゴリは、最大保持することができる
2、複数のバックパック:アイテムの各タイプの数が最大NUMを運ぶことができる限られたクラスIの記事を有する[I]回
3、完全なバックパック:無制限の内袋に入れた項目のそれぞれのカテゴリー
一、0—1背包
アイデアの分析:
主に二つの問題に関連0-1ナップザック問題を解決しました
a)はバックパックの最大のソリューションの内容:
動的プログラミング最適値の方法を使用して。それを仮定dp[N][V]
中間状態値を格納するためにdp[i][j]
フロントを示している私の記事は、容量にロードすることができるJバックパック内の物品の価値の合計最大(最大値に注意)、その後、私たちは知識、最終的な必要dp[i=N][j=V]
要求の対象である値を、 。
今動的プログラミングDPの配列を考慮する[i] [j]は状態遷移式です:
アイテムの容量がJであるバックパックロードする前に、我々は、I-1の最大値の和を計算したとdp[i-1][j]
最初、J固定容量値が変化しないままで、i
:インストール方法アイテムが以下に説明されている
i番目の商品の重量によって、最初重量[I]、すなわち、より少ないジョブjの容量よりも、
1、あればweight[i]>j
私の項目で、確かに、その後、容量のバックパックjを充電されていません、dp[i][j]=dp[i-1][j]
2、あればweight[i]<=j,
最初の明確な項目は、私たちが記事をロードした場合、存在し、その後、Jのロードされたバックパックの容量にできることです
dp[i][j]=dp[i-1][j-weight[i]]+value[i]
アテンダントの問題は、合計値がバックパックで最大であるならば、我々は、Jバックパック後の容量に最初のiの項目を決定しなければならないということですか?さて、私の項目の最初の合計値の後にインストールされている場合、すなわち、決定事実にdp[i-1][j-weight[i]]+value[i]>没装之前的总价值最大值dp[i-1][j]
特に記載項目I-Jの必要充電されていない容量のバックパックをインストールした後に(その後、より小さい合計値を有し;、最大健確かにそれらをインストールする必要はありません)
、次のように、状態遷移方程式は次のとおりです。
dp[i][j] = (dp[i-1][j] > (dp[i-1][j-weight[i]]+value[i]))? dp[i-1][j]:(dp[i-1][j-weight[i]]+value[i])
注:これは与えられた順序で私の項目の前にあります
b)は、物品のID充電バックパックを取得
ここでは、のためならば、に対処するための逆押しのアイデアを使用しdp[i][j]>dp[i-1][j]
、その後、i番目の記事では、バックパックに配置されている必要があり、この時間は、我々は再検討dp[i-1][j-weight[i]
その上に数]。
/**
* 0-1背包问题
* @param V 背包容量
* @param N 物品种类
* @param weight 物品重量
* @param value 物品价值
* @return
*/
public static String ZeroOnePack(int V,int N,int[] weight,int[] value){
//初始化动态规划数组
int[][] dp = new int[N+1][V+1];
//为了便于理解,将dp[i][0]和dp[0][j]均置为0,从1开始计算
for(int i=1;i<N+1;i++){
for(int j=1;j<V+1;j++){
//如果第i件物品的重量大于背包容量j,则不装入背包
//由于weight和value数组下标都是从0开始,故注意第i个物品的重量为weight[i-1],价值为value[i-1]
if(weight[i-1] > j)
dp[i][j] = dp[i-1][j];
else
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weight[i-1]]+value[i-1]);
}
}
//则容量为V的背包能够装入物品的最大值为
int maxValue = dp[N][V];
//逆推找出装入背包的所有商品的编号
int j=V;
String numStr="";
for(int i=N;i>0;i--){
//若果dp[i][j]>dp[i-1][j],这说明第i件物品是放入背包的
if(dp[i][j]>dp[i-1][j]){
numStr = i+" "+numStr;
j=j-weight[i-1];
}
if(j==0)
break;
}
return numStr;
}
自己概要
言うことであり、i番目の項目は、配置されたアレイ内の第1のループ素子は、組み合わせを確認するために、この資料の0〜I-1から最高値を配置することができます。jはバックパックの電流容量といわれ、
このアイテムはバックパックの総容量の電流容量よりも大きい場合は、確かにこの記事を置くことは、極大電流、入って来ていない、現在の値は、この記事では不適切である、であるdp[i-1][j]
私達はそれに入ることができればそれより約マイナス総容量の電流容量であり、次に大きな次に更新した場合、最大値を比較する、物品せずにこの値を追加します。
局所的最適化することを確認してください。