動的計画法における 0-1 ナップザック問題 (体積、重さ、値)

目次

質問要件

質問分析

疑問を解決する

  1. まず、最初の疑問を述べさせてください。

  2. 疑問を解決する

  3. 疑問の理由

他に疑問がある場合は、コメントを残すか、私をフォローしてプライベートメッセージを送ってください。問題を一緒に分析して解決します。

質問コード


質問要件

n 個のアイテムとバックパックが与えられます。アイテム i の重さは wi、体積は bi、その価値は vi、バックパックの容量は c、体積は d です。バックパックに入れるアイテムの合計価値が最大になるように、バックパックに入れるアイテムをどのように選べばよいでしょうか?繰り返すことはできません。入力データの 1 行目は、バックパックの容量 c、バックパックの体積 d、およびアイテムの数 n です。次の n 行は、n 個の品目の重量、体積、および価値を表します。出力は合計の最大値となります。

入力サンプル:

20 15 3

11 7 9

9 5 10

7 10 5

出力サンプル

19

質問分析

1.動的プログラミングの問題への一般的な導入は次のとおりです。以前にやったことを思い出してください。

それは、大きな問題をいくつかの小さな問題に分割し、小さな問題に対する最適な解決策を採用し、小さな問題の最適な解決策を動的に更新される配列 (通常はdp 配列として定義します) に入れて、さらに問題を解決する 問題については、配列に保存されている前のステップの最適解を直接取得するだけで十分です。

利点は、最初の決定がどのようなものであっても、その後の決定に対して最適なソリューションを形成できることです。

2. 本題に戻る

0-1 バックパックは、バックパックの問題の中でも古典的です。このシリーズには、完全なバックパック、複数のバックパックなども含まれています。一部の質問ブラッシング プラットフォームの関連質問の一部は、古典的な質問タイプに修正および装飾されています。

0-1 バックパックには、指定されたアイテムがロードされているかロードされていないかの 2 つの状態のみがあり他の状態はありません。

質問には、重み、体積、および値の 3 つの属性が指定されています (従来の質問タイプよりも体積属性が 1 つ多い)。

前に述べたように、動的プログラミングは、小さな問題をそれぞれ動的に保存するための最適なソリューションです。

それで

(1)まずアイテムがインストールされているかどうかを判断する必要があります (インストールされていない場合、dp 配列は前のステップの最適解をこの状態で保存する必要があります)

(2) 次にインストールすると、次の 2 つの状態になります。

            1.現在のアイテムをロードする前のバックパック内の値が、ロード後の合計値より大きい(その場合、それをロードする必要があります

            2.現在のアイテムをロードする前のバックパック内の値が、ロード後の合計値よりも小さくなります

(どんな小さな問題も最適解を見つける必要があるため、ロードしてはなりません。このとき、dp 配列内の最適解は前の状態の解でなければなりません)

インストールまたは非インストールについては、コード プログラミングで状態遷移方程式 (つまり 2 つの Max) を使用します。

dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - w[i]][k - b[i]] + v[i]);
						

上記のdp[i - 1][j - w[i]][k - b[i]] + v[i] は、項目 i を入力した後の値を 表します。
          dp[i - 1][j][ k]は                            項目iの値が入っていないことを表します

  (3) dp 内のデータの更新には 3 サイクルが必要です。

           0-i 項目、

           バックパックの容量、

           バックパックの容量

       この 3 つのサイクルの恩恵により、dp 配列が更新され、さまざまな条件下で最適なソリューションを選択できるようになります。

    

疑問を解決する

 1. まず、最初の疑問を述べさせてください。

    dp 配列を更新するコード内のトリプル ループで、バックパック容量 j++ とバックパック容量 k++ が毎回 1 ずつ増加するのはなぜですか?

    アイテムが積載されているかどうかについては、バックパックの容量、バックパックの体積に、指定されたアイテム i の属性を加えたものが通常の理解ではないでしょうか。

 2. 疑問を解決する

     その後の理解で疑問が解決しました

まず、dp配列にはバックパックの各段(彼が被験者)の最適解が     読み込まれているため、このときのdp配列は3次元の直方体になります。

    dp 配列に格納されるのは、追加の重量単位および体積の各単位に対する、現時点でのナップザック問題の最適解です

  3. 疑問の理由

     通常の先入観の考え方は動的計画法の中心から外れており、バックパックが本体であり、オブジェクトは外部にすぎません。

他に疑問がある場合は、コメントを残すか、私をフォローしてプライベートメッセージを送ってください。問題を一緒に分析して解決します。

質問コード

#include <iostream>
#include <cmath>
using namespace std;
const int TOF = 105;

int dp[TOF][TOF][TOF] = {0};//初始化,三维数组有上限
int w[TOF], b[TOF] ,v[TOF]; //w代表重量,b代表体积,v代表价值


int main()
{
    int i, j, k;
    int n, c, d;//c代表背包容量,d代表背包容积
    
    cin >> c >> d>> n;  
    for (i = 1; i < n + 1; i++)
    {
        cin >> w[i] >> b[i] >> v[i];
    }

	for ( i = 1; i <= n; i++)
			for ( j = c; j >= 0; j--)
				for( k = d; k >= 0;  k--)
				{
					if (j >= w[i]&&k >= b[i])
				    {
			     		dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - w[i]][k - b[i]] + v[i]);
						//dp[i - 1][j - w[i]][k - b[i]] + v[i]  放入i物品后的价值
						//dp[i - 1][j][k]  没有放入i物品的价值
				    }
				    else
				   {
				 	     dp[i][j][k] = dp[i - 1][j][k];
				   }
				}
				
   
    cout << "背包能放物品的最大价值为:" << dp[n][c][d] << endl;
   
}

皆さんコメント大歓迎です、迷わないようフォローして一緒に進歩していきましょう!

皆さんコメント大歓迎です、迷わないようフォローして一緒に進歩していきましょう!

皆さんコメント大歓迎です、迷わないようフォローして一緒に進歩していきましょう!

おすすめ

転載: blog.csdn.net/weixin_59367964/article/details/127966238