基礎揹包問題 - 0-1 揹包問題 - 深度優先搜索 (遞歸)
1. 基礎揹包問題
有 N
件物品和一個承受最大重量爲 W
的揹包。第 i
件物品的重量是 w[i]
,價值是 v[i]
。求解將哪些物品裝入揹包可使這些物品的重量總和不超過揹包容量,且價值總和最大。
揹包問題 (Knapsack problem) 是一種組合優化的 NP 完全問題。給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內,我們如何選擇,才能使得物品的總價格最高。
如果限定每種物品只能選擇 0 個或 1 個,則問題稱爲 0-1 揹包問題 (0-1 knapsack problem) 。
如果限定物品 j
最多隻能選擇 maxj
個,則問題稱爲有界揹包問題 (bounded knapsack problem,BKP)。
如果不限定每種物品的數量,每種物品都就可以選擇任意多個,則問題稱爲無界揹包問題或完全揹包問題 (unbounded knapsack problem,UKP)。
2. 0-1 揹包問題
2.1 基本思路
最基礎的揹包問題,每種物品僅有一件,可以選擇放或不放。利用遞歸針對每個物品是否放入揹包進行兩種情況下的搜索。0-1 揹包問題在選第 i 個物品時,只有 2 種狀態可選,放還是不放。
2 // 測試用例個數
4 5 // N = 4 物品的類別數,W = 5 揹包承受的最大重量,最大價值 7
2 3 // w[0] = 2,v[0] = 3
1 2 // w[1] = 1,v[1] = 2
3 4 // w[2] = 3,v[2] = 4
2 2 // w[3] = 2,v[3] = 2
5 8 // N = 5 物品的類別數,W = 8 揹包承受的最大重量,最大價值 10
3 4
5 5
1 2
2 1
2 3
2
4 5
2 3
1 2
3 4
2 2
5 8
3 4
5 5
1 2
2 1
2 3
2.2 dfs_v1
算法遍歷的組合數爲 ,計算複雜度大。
/*
============================================================================
Name : yongqiang.cpp
Author : Yongqiang Cheng
Version : Version 1.0.0
Copyright : Copyright (c) 2020 Yongqiang Cheng
Description : Hello World in C++, Ansi-style
============================================================================
*/
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <time.h>
using namespace std;
int computation = 0;
void dfs_v1(int map[100][2], int N, int W, int sumweight, int sumvalue, int *max_value, int count, int book[100])
{
if (count >= N)
{
computation++;
if ((sumweight <= W) && (sumvalue > *max_value))
{
*max_value = sumvalue;
}
return;
}
if (0 == book[count])
{
int addvalue = 0, addweight = 0;
// select
addvalue = map[count][1];
addweight = map[count][0];
book[count] = 1;
dfs_v1(map, N, W, sumweight + addweight, sumvalue + addvalue, max_value, count + 1, book);
book[count] = 0;
// unselect
addvalue = 0;
addweight = 0;
book[count] = 1;
dfs_v1(map, N, W, sumweight, sumvalue, max_value, count + 1, book);
book[count] = 0;
}
return;
}
int inference(int map[100][2], int N, int W)
{
int ret = 0;
int max_value = INT_MIN;
int count = 0;
int sumweight = 0;
int sumvalue = 0;
int book[100] = { 0 };
dfs_v1(map, N, W, sumweight, sumvalue, &max_value, count, book);
ret = max_value;
return ret;
}
int main()
{
clock_t start = 0, end = 0;
double cpu_time_used = 0;
const char input_txt[] = "D:\\visual_studio_workspace\\yongqiangcheng\\yongqiangcheng\\input.txt";
const char output_txt[] = "D:\\visual_studio_workspace\\yongqiangcheng\\yongqiangcheng\\output.txt";
freopen(input_txt, "r", stdin);
// freopen(output_txt, "w", stdout);
start = clock();
printf("Start of the program, start = %ld\n", start);
printf("Start of the program, start = %ld\n\n", start);
int case_num;
cin >> case_num;
for (int i = 1; i <= case_num; i++)
{
int ret = 0;
int N = 0, W = 0;
int map[100][2] = { 0 };
computation = 0;
cin >> N >> W;
for (int h = 0; h < N; h++)
{
cin >> map[h][0] >> map[h][1]; // weight - value
}
ret = inference(map, N, W);
cout << "computation " << i << " = " << computation << endl;
cout << "CASE #" << i << " = " << ret << endl;
}
end = clock();
printf("\nEnd of the program, end = %ld\n", end);
printf("End of the program, end = %ld\n", end);
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Total time taken by CPU: %f\n", cpu_time_used);
printf("Exiting of the program...\n");
fclose(stdin);
// fclose(stdout);
return 0;
}
Start of the program, start = 9
Start of the program, start = 9
computation 1 = 16
CASE #1 = 7
computation 2 = 32
CASE #2 = 10
End of the program, end = 15
End of the program, end = 15
Total time taken by CPU: 0.006000
Exiting of the program...
請按任意鍵繼續. . .
2.3 dfs_v2
/*
============================================================================
Name : yongqiang.cpp
Author : Yongqiang Cheng
Version : Version 1.0.0
Copyright : Copyright (c) 2020 Yongqiang Cheng
Description : Hello World in C++, Ansi-style
============================================================================
*/
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <time.h>
using namespace std;
int computation = 0;
void dfs_v2(int map[100][2], int N, int W, int sumweight, int sumvalue, int *max_value, int count, int book[100])
{
if (sumweight > W)
{
return;
}
if (count >= N)
{
computation++;
if (sumvalue > *max_value)
{
*max_value = sumvalue;
}
return;
}
if (0 == book[count])
{
int addvalue = 0, addweight = 0;
// select
addvalue = map[count][1];
addweight = map[count][0];
book[count] = 1;
dfs_v2(map, N, W, sumweight + addweight, sumvalue + addvalue, max_value, count + 1, book);
book[count] = 0;
// unselect
addvalue = 0;
addweight = 0;
book[count] = 1;
dfs_v2(map, N, W, sumweight, sumvalue, max_value, count + 1, book);
book[count] = 0;
}
return;
}
int inference(int map[100][2], int N, int W)
{
int ret = 0;
int max_value = INT_MIN;
int count = 0;
int sumweight = 0;
int sumvalue = 0;
int book[100] = { 0 };
dfs_v2(map, N, W, sumweight, sumvalue, &max_value, count, book);
ret = max_value;
return ret;
}
int main()
{
clock_t start = 0, end = 0;
double cpu_time_used = 0;
const char input_txt[] = "D:\\visual_studio_workspace\\yongqiangcheng\\yongqiangcheng\\input.txt";
const char output_txt[] = "D:\\visual_studio_workspace\\yongqiangcheng\\yongqiangcheng\\output.txt";
freopen(input_txt, "r", stdin);
// freopen(output_txt, "w", stdout);
start = clock();
printf("Start of the program, start = %ld\n", start);
printf("Start of the program, start = %ld\n\n", start);
int case_num;
cin >> case_num;
for (int i = 1; i <= case_num; i++)
{
int ret = 0;
int N = 0, W = 0;
int map[100][2] = { 0 };
computation = 0;
cin >> N >> W;
for (int h = 0; h < N; h++)
{
cin >> map[h][0] >> map[h][1]; // weight - value
}
ret = inference(map, N, W);
cout << "computation " << i << " = " << computation << endl;
cout << "CASE #" << i << " = " << ret << endl;
}
end = clock();
printf("\nEnd of the program, end = %ld\n", end);
printf("End of the program, end = %ld\n", end);
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Total time taken by CPU: %f\n", cpu_time_used);
printf("Exiting of the program...\n");
fclose(stdin);
// fclose(stdout);
return 0;
}
Start of the program, start = 8
Start of the program, start = 8
computation 1 = 12
CASE #1 = 7
computation 2 = 23
CASE #2 = 10
End of the program, end = 12
End of the program, end = 12
Total time taken by CPU: 0.004000
Exiting of the program...
請按任意鍵繼續. . .
2.4 dfs_v3
/*
============================================================================
Name : yongqiang.cpp
Author : Yongqiang Cheng
Version : Version 1.0.0
Copyright : Copyright (c) 2020 Yongqiang Cheng
Description : Hello World in C++, Ansi-style
============================================================================
*/
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <time.h>
using namespace std;
int computation = 0;
void dfs_v3(int map[100][2], int N, int W, int sumweight, int sumvalue, int *max_value, int count, int book[100])
{
if (sumweight > W)
{
return;
}
if (count >= N)
{
computation++;
if (sumvalue > *max_value)
{
*max_value = sumvalue;
}
return;
}
if (0 == book[count])
{
int addvalue = 0, addweight = 0;
// select
addvalue = map[count][1];
addweight = map[count][0];
if ((sumweight + addweight) <= W)
{
book[count] = 1;
dfs_v3(map, N, W, sumweight + addweight, sumvalue + addvalue, max_value, count + 1, book);
book[count] = 0;
}
// unselect
addvalue = 0;
addweight = 0;
book[count] = 1;
dfs_v3(map, N, W, sumweight, sumvalue, max_value, count + 1, book);
book[count] = 0;
}
return;
}
int inference(int map[100][2], int N, int W)
{
int ret = 0;
int max_value = INT_MIN;
int count = 0;
int sumweight = 0;
int sumvalue = 0;
int book[100] = { 0 };
dfs_v3(map, N, W, sumweight, sumvalue, &max_value, count, book);
ret = max_value;
return ret;
}
int main()
{
clock_t start = 0, end = 0;
double cpu_time_used = 0;
const char input_txt[] = "D:\\visual_studio_workspace\\yongqiangcheng\\yongqiangcheng\\input.txt";
const char output_txt[] = "D:\\visual_studio_workspace\\yongqiangcheng\\yongqiangcheng\\output.txt";
freopen(input_txt, "r", stdin);
// freopen(output_txt, "w", stdout);
start = clock();
printf("Start of the program, start = %ld\n", start);
printf("Start of the program, start = %ld\n\n", start);
int case_num;
cin >> case_num;
for (int i = 1; i <= case_num; i++)
{
int ret = 0;
int N = 0, W = 0;
int map[100][2] = { 0 };
computation = 0;
cin >> N >> W;
for (int h = 0; h < N; h++)
{
cin >> map[h][0] >> map[h][1]; // weight - value
}
ret = inference(map, N, W);
cout << "computation " << i << " = " << computation << endl;
cout << "CASE #" << i << " = " << ret << endl;
}
end = clock();
printf("\nEnd of the program, end = %ld\n", end);
printf("End of the program, end = %ld\n", end);
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Total time taken by CPU: %f\n", cpu_time_used);
printf("Exiting of the program...\n");
fclose(stdin);
// fclose(stdout);
return 0;
}
Start of the program, start = 9
Start of the program, start = 9
computation 1 = 12
CASE #1 = 7
computation 2 = 23
CASE #2 = 10
End of the program, end = 12
End of the program, end = 12
Total time taken by CPU: 0.003000
Exiting of the program...
請按任意鍵繼續. . .