[C/C++ 演算法]- 背包問題(Knapsack Problem)
[C/C++ 演算法]- 背包問題(Knapsack Problem)
剛才找資料時發現一個C/C++的教學網站,趕快發揮(C/P)的長才將它備份來,有需要的同好,歡迎來(C/P)一下^^。
拷貝來源:
http://openhome.cc/Gossip/AlgorithmGossip/
http://openhome.cc/Gossip/AlgorithmGossip/KnapsackProblem.htm
https://blog.xuite.net/victorfm/victor/15177002-%E5%8B%95%E6%85%8B%E8%A6%8F%E5%8A%83++–+%E8%83%8C%E5%8C%85%E5%95%8F%E9%A1%8C
線上執行: https://www.tutorialspoint.com/compile_c_online.php
#include <stdio.h>
#include <stdlib.h>
#define LIMIT 8 // 重量限制
typedef struct {
char name[20];
int weight;
int price;
} Fruit;
void knapsack(Fruit*, int*, int*, int, int);
int min(Fruit*, int);
int main(void) {
Fruit fruits[] = {{"李子", 4, 4500},
{"蘋果", 5, 5700},
{"橘子", 2, 2250},
{"草莓", 1, 1100},
{"甜瓜", 6, 6700}};
int items[LIMIT + 1] = {0};
int values[LIMIT + 1] = {0};
int length = sizeof(fruits) / sizeof(fruits[0]);
knapsack(fruits, values, items, length, LIMIT);
printf("物品\t價格\n");
int i;
for(i = LIMIT; i >= min(fruits, length); i -= fruits[items[i]].weight) {
printf("%s\t%d\n", fruits[items[i]].name, fruits[items[i]].price);
}
printf("合計\t%d\n", values[LIMIT]);
return 0;
}
void knapsack(Fruit* fruits, int* values, int* items,
int length, int limit) {
int i, w;
for(i = 0; i < length; i++) {
for(w = fruits[i].weight; w <= limit; w++) {
int p = w - fruits[i].weight;
int newValue = values[p] + fruits[i].price;
if(newValue > values[w]) { // 找到階段最佳解
values[w] = newValue;
items[w] = i;
}
}
}
}
int min(Fruit* fruits, int length) {
int i, m;
for(i = 0, m = fruits[0].weight; i < length; i++) {
if(fruits[i].weight < m) {
m = fruits[i].weight;
}
}
return m;
}
—————–
說明
假設有一個背包的負重最多可達
總價物品,假設是水果好了,水果的編號、單價與重量如下所示:
|
0 |
李子 |
|
NT$4500 |
|
1 |
蘋果 |
|
NT$5700 |
|
2 |
橘子 |
|
NT$2250 |
|
3 |
草莓 |
|
NT$1100 |
|
4 |
甜瓜 |
|
NT$6700 |
解法
背包問題是關於最佳化的問題,要解最佳化問題可以使用「動態規劃」
(Dynamic programming),從空集合開始,每增加一個元素就先求出該
階段的最佳解,直到所有的元素加入至集合中,最後得到的就是最佳解。
以背包問題為例,我們使用兩個陣列value與item,value表示目前的最
佳解所得之總價,item表示最後一個放至背包的水果,假設有負重量 1~8
的背包8個,並對每個背包求其最佳解。
逐步將水果放入背包中,並求該階段的最佳解:
- 放入李子
|
背包負重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
|
value |
0 |
0 |
0 |
4500 |
4500 |
4500 |
4500 |
9000 |
|
item |
- |
- |
- |
0 |
0 |
0 |
0 |
0 |
- 放入蘋果
|
背包負重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
|
value |
0 |
0 |
0 |
4500 |
5700 |
5700 |
5700 |
9000 |
|
item |
- |
- |
- |
0 |
1 |
1 |
1 |
0 |
- 放入橘子
|
背包負重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
|
value |
0 |
2250 |
2250 |
4500 |
5700 |
6750 |
7950 |
9000 |
|
item |
- |
2 |
2 |
0 |
1 |
2 |
2 |
0 |
- 放入草莓
|
背包負重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
|
value |
1100 |
2250 |
3350 |
4500 |
5700 |
6800 |
7950 |
9050 |
|
item |
3 |
2 |
3 |
0 |
1 |
3 |
2 |
3 |
- 放入甜瓜
|
背包負重 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
|
value |
1100 |
2250 |
3350 |
4500 |
5700 |
6800 |
7950 |
9050 |
|
item |
3 |
2 |
3 |
0 |
1 |
3 |
2 |
3 |
由最後一個表格,可以得知在背包負重8公斤時,最多可以裝入9050元的水果,而最後一個裝入的水果是3號,也就是草莓,裝入了草莓,背包只能再放入
#include <stdio.h>
#include <stdlib.h>
#define LIMIT 8 // 重量限制
#define N 5 // 物品種類
#define MIN 1 // 最小重量
struct body {
char name[20];
int size;
int price;
};
typedef struct body object;
object a[] = {{"李子", 4, 4500},
{"蘋果", 5, 5700},
{"橘子", 2, 2250},
{"草莓", 1, 1100},
{"甜瓜", 6, 6700}};
int item[LIMIT+1] = {0};
int value[LIMIT+1] = {0};
int newvalue, i, s, p;
int main(void) {
for(i = 0; i < N; i++) {
for(s = a[i].size; s <= LIMIT; s++) {
p = s - a[i].size;
newvalue = value[p] + a[i].price;
if(newvalue > value[s]) {// 找到階段最佳解
value[s] = newvalue;
item[s] = i;
}
}
}
printf("物品\t價格\n");
for(i = LIMIT; i >= MIN; i = i - a[item[i]].size) {
printf("%s\t%d\n",
a[item[i]].name, a[item[i]].price);
}
printf("\n合計\t%d\n", value[LIMIT]);
return 0;
}
心得:
原版程式寫得真好,解說版超詳細 都非常值得收藏
2 thoughts on “[C/C++ 演算法]- 背包問題(Knapsack Problem)”
暴力解法:
[C/C++演算法]-想問這題怎麼寫? AX+BY+CZ ≦Dividend
https://bit.ly/31vcnet
暴力/貪心 演算法 的 替代 / 取代
暴力演算法(暴力算法)
貪心演算法(貪心算法)