2016-03-29 5 views
0

私はこのアルゴリズムをテキストブックから実装しようとしています。再帰アルゴリズムを使ってナップザックを解く

enter image description here

私はこれを書いた:ここ

// Knapsack_memoryfunc.cpp : Defines the entry point for the console application. 
//Solving Knapsack problem using dynamic programmig and Memory function 

#include "stdafx.h" 
#include "iostream" 
#include "iomanip" 
using namespace std; 

int table[20][20] = { 0 }; 
int value, n, wt[20], val[20], max_wt; 

// ---CONCERNED FUNCTION----- 

int MNSack(int i, int j) 
{ 
    value = 0; 
    if (table[i][j] < 0) 
     if (j < wt[i]) 
      value = MNSack(i - 1, j); 
     else 
      value = fmax(MNSack(i - 1, j), val[i] + MNSack(i - 1, j - wt[i])); 

    table[i][j] = value; 
    return table[i][j]; 
} 

// -------------------------- 

void items_picked(int n, int max_wt) 
{ 
    cout << "\n Items picked : " << endl; 
    while (n > 0) 
    { 
     if (table[n][max_wt] == table[n - 1][max_wt]) // if value doesnot change in table column-wise, item isn't selected 
      n--;          // n-- goes to next item 
     else           // if it changes, it is selected 
     { 
      cout << " Item " << n << endl; 
      max_wt -= wt[n];       // removing weight from total available (max_wt) 
      n--;          // next item 
     } 
    } 
} 

int main() 
{ 

    cout << " Enter the number of items : "; 
    cin >> n; 
    cout << " Enter the Maximum weight : "; 
    cin >> max_wt; 
    cout << endl; 
    for (int i = 1; i <= n; i++) 
    { 
     cout << " Enter weight and value of item " << i << " : "; 
     cin >> wt[i] >> val[i]; 
    } 

    for (int i = 0; i <= n; i++) 
     for (int j = 0; j <= max_wt; j++) 
      table[i][j] = 0; 

    for (int i = 1; i <= n; i++) 
     for (int j = 1; j <= max_wt; j++) 
      table[i][j] = -1; 

    cout << " Optimum value : " << MNSack(n, max_wt); 

    cout << " \n Table : \n"; 
    for (int i = 0; i <= n; i++) 
    { 
     for (int j = 0; j <= max_wt; j++) 
      if (table[i][j] == -1) 
       cout << setw(5) << "-"; 
      else 
       cout << setw(5) << table[i][j]; 
     cout << endl; 
    } 

    items_picked(n, max_wt); 


    return 0; 
} 

は、質問と出力されます:
enter image description here

それは最適値のようないくつかの場所でその正しいように思える、まだないです十分に受け入れられる。 私はそれをデバッグしようとしましたが、再帰的な関数では非常に難しいです。誰かが助けてくれますか?

+0

ヘイリー、私はヘンリーリーの答えは正しいと思っていますが、それでも後であなたに何かを与えたいと思っています。 Urコードはちょっとひどく、この問題を解決する方法はプログラマーの下でのメモ作成と呼ばれています。これは私をたくさん助け、コードの美しさをより美しくすることができる美しいblogpostです。 http://programminggenin.blogspot.de/2013/01/memoization-in-c.html – Mehno

+0

@Mehnoあなたは精緻化できますか?アルゴリズムは、私が理解するように、必要な値だけを計算します。どのように私はそれを実装することができますか? – LonelyC

+0

@Mehnoはあなたのコーディングスタイルをより良くするテクニックを提案しました。あなたのアルゴリズムに悪いことはありません。しかし、興味があれば、同じ問題を解決するためにボトムアップの動的プログラミングを使用する方法を示し、行数はごくわずかであり、コードをはるかに良くすることができます。 – HenryLee

答えて

1
int MNSack(int i, int j) 
{ 
    value = 0; 
    if (table[i][j] < 0) 
    { 
     if (j < wt[i]) 
      value = MNSack(i - 1, j); 
     else 
      value = max(MNSack(i - 1, j), val[i] + MNSack(i - 1, j - wt[i])); 

     table[i][j] = value; 
    } 
    return table[i][j]; 
} 

ここに問題があります。テーブルアイテムが0より大きい場合、再帰はスキップされますが、テーブルアイテムが0より大きい場合でもテーブルアイテムは0より大きくなります。

テーブル項目を変更する必要があるときは、中括弧に入れてこれを修正します。

1

ボトムアップ溶液。

#include <iostream> 
#include <algorithm> 
#include <iomanip> 
using namespace std; 


int main() 
{ 
    int table[20][20] = { 0 }; 
    int value, n, wt[20], val[20], max_wt; 

    cout << " Enter the number of items : "; 
    cin >> n; 
    cout << " Enter the Maximum weight : "; 
    cin >> max_wt; 
    cout << endl; 
    for (int i = 1; i <= n; i++) 
    { 
     cout << " Enter weight and value of item " << i << " : "; 
     cin >> wt[i] >> val[i]; 
    } 

    // Initialization 
    for (int i = 0; i <= n; i++) 
     for (int j = 0; j <= max_wt; j++) 
      table[i][j] = 0; 

    // In practice, this can be skipped in a bottom up solution 
    for (int i = 1; i <= n; i++) 
     for (int j = 1; j <= max_wt; j++) 
      table[i][j] = -1; 

    for (int i = 1; i <= n; i++) 
    { 
     for (int j = 1; j <= max_wt; j++) 
     { 
      if (j < wt[i]) 
       table[i][j] = table[i - 1][j]; 
      else 
       table[i][j] = max(table[i - 1][j], val[i] + table[i - 1][j - wt[i]]); 
     } 
    } 

    cout << " Optimum value : " << table[n][max_wt] << endl; 

    cout << " \n Table : \n"; 
    for (int i = 0; i <= n; i++) 
    { 
     for (int j = 0; j <= max_wt; j++) 
      if (table[i][j] == -1) 
       cout << setw(5) << "-"; 
      else 
       cout << setw(5) << table[i][j]; 
     cout << endl; 
    } 

    return 0; 
} 

これは再帰をループに変更し、グローバル変数を避けることがわかります。また、コードが簡単になるため、テーブル項目が有効かどうかをチェックすることもできます(例では-1)。

このソリューションの欠点は、常にすべての可能なノードを横断することです。しかし、再帰とテーブル項目の二重チェックがより多くのコストを要するため、項目ごとにより良い係数が得られます。トップダウンとボトムアップはどちらも同じオーダーの複雑さO(n^2)を持ち、どれが速いのかを判断するのは難しいです。

+0

ちょっと!再帰的方法を調べる前に、この問題を解決するために実際にこの正確な方法を使用しました。再帰を使用してこれを行うことは可能で、グローバル変数は使用できませんか? – LonelyC

+0

@LonelyC聞いてよかったです。グローバル変数を使用せずに実行することは常に可能です。変数を各関数のパラメータとして渡すだけです。パラメータの値を変更する必要がある場合は、代わりに変数の参照(またはCのポインタ)を渡す必要があることに注意してください。この例では、テーブル内の値を変更するだけで済みます。テーブルはポインタとして渡されるため、そのことを心配する必要はありません。 – HenryLee

+0

ああそう!わかりました。すべての助けをありがとう:) – LonelyC

関連する問題