2016-03-29 60 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

Heyho,我认为HenryLee的回答是正确的,但它仍然希望稍后给你一些东西。 Ur代码有点可怕,而你解决这个问题的方式在程序员之下被称为memoization。这是一个美丽的博客帖子,它帮助了我很多,可以让你的代码更加美丽。 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