1. 程式人生 > >動態規劃0—1揹包問題

動態規劃0—1揹包問題

                                                                 動態規劃0-1揹包問題

Ø    問題描述:    給定n種物品和一揹包。物品i的重量是wi,其價值為vi,揹包的容量為C。問應如何選擇裝入揹包的物品,使得裝 入揹包中物品的總價值最大? Ø   對於一種物品,要麼裝入揹包,要麼不裝。所以對於一種物品的裝入狀態可以取0和1.我們設物品i的裝入狀態為xi,xi∈ (0,1),此問題稱為0-11揹包問題。                                過程分析

    資料:物品個數n=5,物品重量w[n]={0,2,2,6,5,4},物品價值V[n]={0,6,3,5,4,6},

     (第0位,置為0,不參與計算,只是便於與後面的下標進行統一,無特別用處,也可不這麼處理。)總重量c=10.

Ø揹包的最大容量為10,那麼在設定陣列m大小時,可以設行列值為6和11,那麼,對於m(i,j)就表示可選物品為i…n揹包容量為j(總重量)時揹包中所放物品的最大價值。

                                         

下面寫點,我對動態規劃淺薄的理解,希望看到這篇文章的同學們,能更容易理解這個演算法思想。

首先,要明白這個演算法的核心,我建議首先要會暴力求最值的演算法,就是用搜索去求最值的演算法,不管是用dfs,還是bfs,都可以,首先你要建立一個狀態的概念,搜尋中就會有這個概念,明白從一個狀態到一個狀態怎麼搜尋,怎麼求。動態規劃的實質就是,將問題化為求解子問題,前一個子問題最值問題求解了,如果你找到子問題與當前問題的關係,那麼當前問題就解決了,是一個迭代的過程。另外,將搜尋進行記憶化,其實也是一種dp的思想,我覺得首先你得了解記憶化搜尋的思想,才能入得了動態規劃的門,明白啦這個思想之後,後面的東西你慢慢就領悟啦,不然老是說dp,看了一遍,覺得懂了,下次又忘啦,其實就是用空間換時間的一種搜尋而已,很簡單的思想。

下面是自己寫的原始碼:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<queue>
#include<climits>
#include<cstring>
using namespace std;
const int c = 10;             //揹包的容量
const int w[] = {0,2,2,6,5,4};//物品的重量,其中0號位置不使用 。 
const int v[] = {0,6,3,5,4,6};//物品對應的待加,0號位置置為空。
const int n = sizeof(w)/sizeof(w[0]) - 1 ; //n為物品的個數 
int x[n+1];
void package0_1(int m[][11],const int w[],const int v[],const int n)//n代表物品的個數 
{
    //採用從底到頂的順序來設定m[i][j]的值
    //首先放w[n]
    for(int j = 0; j <= c; j++)
       if(j < w[n]) m[n][j] = 0;     //j小於w[n],所對應的值設為0,否則就為可以放置 
       else         m[n][j] = v[n];
       
    //對剩下的n-1個物品進行放置。
    int i;
    for(i = n-1; i >= 1; i--)
        for(int j = 0; j <= c; j++)
           if(j < w[i]) 
                        m[i][j] = m[i+1][j];//如果j < w[i]則,當前位置就不能放置,它等於上一個位置的值。
                                            //否則,就比較到底是放置之後的值大,還是不放置的值大,選擇其中較大者。            
           else         m[i][j] = m[i+1][j] > m[i+1][j-w[i]] + v[i]? 
                                  m[i+1][j] : m[i+1][j-w[i]] + v[i];  
}
void answer(int m[][11],const int n)
{
    int j = c;
    int i;
    for(i = 1; i <= n-1; i++)
        if(m[i][j] == m[i+1][j]) x[i] = 0;
        else                    { 
                                 x[i] = 1;
                                 j = j - w[i];
                                 }    
    x[n] = m[i][j] ? 1 : 0; 
}
int main()
{
 int m[6][11]={0};
 
 package0_1(m,w,v,n);
 for(int i = 0; i <= 5; i++)
 {
     for(int j = 0; j <= 10; j++)
     printf("%2d ",m[i][j]);
     cout << endl; 
 } 
 answer(m,n);
 cout << "The best answer is:\n";
 for(int i = 1; i <= 5; i++)
 cout << x[i] << " ";
 system("pause");
 return 0;
}