0-1揹包的最優解DP解法(C語言)

1. 問題描述

  • 定義

    揹包問題(來自於百度百科)

    有N件物品和一個容量爲V的揹包。第i件物品的重量是w[i],價值是v[i]。求解將哪些物品裝入揹包可使這些物品的重量總和不超過揹包容量,且價值總和最大。

  • 分析

    1. 我們要獲取這個問題的最優解, 也就是最佳的價值
    2. 可以使用貪婪算法對其進行一個遍歷
    3. 在遍歷時, 每當遇到一個物品的時候, 可分爲裝這個東西, 還是不裝這個東西.
    4. 遍歷時, 我們可以將這個問題產生的結果構成一顆二叉樹, 因爲每當遇到一個物品的時候,我們總是能將其分解成, 裝這個物品, 還是不裝這個物品.
    5. 當我們遍歷完成後, 所產生的最優解一定是最後的葉子結點中的一個.

2. 計算方法

  • DP計算公式
    DP公式

    • 對上述公式的說明
      • B(k, w) 表示的是我們的揹包問題的最優解, 其中k, 表示第k個物品, w表示揹包裏面還能裝的下的重量.
      • B(k - 1, w - wk) + vk 的意思就是, 如果裝的話, 將這個第k個物品的重量(wk) 裝上, 加上這個物品的一個價值, 此時揹包中還能裝下的質量爲w - wk
      • 如果不裝的話, 此時揹包裏面就剩餘w個重量
  • 最優解的表格, 我們以下面這個例子來說明

    重量 2 3 4 5 9
    價值 3 4 5 8 10
    編號 1 2 3 4 5
    揹包容量 20
  • 對於以上這個例子, 我們可以得到下面這個表格
    最優解集

    • 對於以上這個表格
      • 其中行表示的是物品的編號, 列表示的是揹包所佔有的容量
      • 每一個格子中的數字表示最大的數字, 就是我們的最優解
      • 比如行爲3, 列爲5的時候, 格子中表示的數字就是, 只佔用5個揹包容量, 只裝前三個物品, 能夠得到的最大的價值
      • 那麼對於整一個問題的最優解就是我們在所有的物品裏面做出選擇, 利用所有的揹包容量來裝, 得到的最大的價值, 就是表格的最右下角的那個格子的值
  • 下面我們就用代碼來求解一下上述的例子

3. 代碼

下面使用c語言實現一下

#include <stdio.h>
#include <stdlib.h>
#define N 6  // rows is 6
#define W 21 // column is 21

// global varables
int Bs[N][W] = {0}; // initialize the table which can show our max value
int weight[6] = {0, 2, 3, 4, 5, 9}; // weight of every goods
int values[6] = {0, 3, 4, 5, 8, 10}; // value of every goods

// calculate max value and fill the table
void knapsack() {
	int k, C;// c is capacity, k is number of goods
	for (k = 1; k < N; k++) {
		for (C = 1; C < W; C++) {
			// cannot load
			if (weight[k] > C) {
				Bs[k][C] = Bs[k - 1][C];
			}
			else {
				// decide which is better if we load current goods
				int value1 = Bs[k - 1][C - weight[k]] + values[k];
				int value2 = Bs[k - 1][C];
				if (value1 > value2) {
					Bs[k][C] = value1;
				}
				else {
					// not load
					Bs[k][C] = value2;
				}
			}
		}
	}
}


// show the max value table
void printBs() {
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < W; j++) {
			printf("%2d ", Bs[i][j]);
		}
		printf("\n");
	}
}

int main(int argc, char const *argv[])
{
	knapsack();
	// show the max values
	printf("The max value is %d\n", Bs[5][20]);
	printf("The max values table is the following \n");
	printBs();
	return 0;
}       

4. 總結

  • 以上代碼雖然能夠求得一個最優解, 最大值, 但是我們並不能直觀的展示具體裝了那個物品.
  • 這個方法, 使用了一個一個遍歷, 對於每一個物品以及每一個容量都進行了遍歷迭代, 複雜度較高
  • 會再繼續學習, 取得更好的解法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章