first commit

This commit is contained in:
2025-12-18 16:00:22 +08:00
commit 785f306726
69 changed files with 33171 additions and 0 deletions

159
dynamic/knapsack.cpp Normal file
View File

@ -0,0 +1,159 @@
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <chrono>
#include <random>
struct Item {
int weight; // 物品重量
int value; // 物品价值
int count; // 物品数量(用于多重背包问题)
};
// 全局操作计数器,用于性能分析
long long ops_count = 0;
// =================================================================
// 完全背包问题算法实现
// =================================================================
// 算法1朴素动态规划三层循环
int complete_knapsack_v1(const std::vector<Item>& items, int capacity) {
ops_count = 0; // 重置操作计数器
int n = items.size();
if (n == 0) return 0;
std::vector<std::vector<int>> dp(n + 1, std::vector<int>(capacity + 1, 0));
// 遍历每个物品
for (int i = 1; i <= n; ++i) {
int w = items[i - 1].weight;
int v = items[i - 1].value;
// 遍历每个容量
for (int j = 0; j <= capacity; ++j) {
dp[i][j] = dp[i-1][j]; // 不选择第i个物品
ops_count++;
// 尝试选择k个第i个物品
for (int k = 1; k * w <= j; ++k) {
ops_count++;
if (dp[i-1][j - k * w] + k * v > dp[i][j]) {
dp[i][j] = dp[i-1][j - k * w] + k * v;
}
}
}
}
return dp[n][capacity];
}
// 算法2优化的二维动态规划两层循环
int complete_knapsack_v2(const std::vector<Item>& items, int capacity) {
ops_count = 0; // 重置操作计数器
int n = items.size();
if (n == 0) return 0;
std::vector<std::vector<int>> dp(n + 1, std::vector<int>(capacity + 1, 0));
// 遍历每个物品
for (int i = 1; i <= n; ++i) {
int w = items[i - 1].weight;
int v = items[i - 1].value;
// 遍历每个容量
for (int j = 0; j <= capacity; ++j) {
ops_count++;
if (j < w) {
dp[i][j] = dp[i - 1][j]; // 容量不足不能选择第i个物品
} else {
// 选择不选第i个物品或选择第i个物品的最大值
dp[i][j] = std::max(dp[i - 1][j], dp[i][j - w] + v);
}
}
}
return dp[n][capacity];
}
// 算法3空间优化的动态规划一维数组
int complete_knapsack_v3(const std::vector<Item>& items, int capacity) {
ops_count = 0; // 重置操作计数器
std::vector<int> dp(capacity + 1, 0); // 一维DP数组
// 遍历每个物品
for (const auto& item : items) {
// 从物品重量开始遍历容量(完全背包)
for (int j = item.weight; j <= capacity; ++j) {
ops_count++;
dp[j] = std::max(dp[j], dp[j - item.weight] + item.value);
}
}
return dp[capacity];
}
// =================================================================
// 基准测试运行器
// =================================================================
void run_experiments(int min_n, int max_n, int step_n, int trials, int capacity) {
// 初始化随机数生成器
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> weight_dist(1, 40); // 重量范围1-40
std::uniform_int_distribution<> value_dist(1, 100); // 价值范围1-100
// 输出CSV格式的表头
std::cout << "n,algo,time_us,ops\n";
// 对不同物品数量进行测试
for (int n = min_n; n <= max_n; n += step_n) {
if (n==0) continue;
long long total_time_v1 = 0, total_ops_v1 = 0;
long long total_time_v2 = 0, total_ops_v2 = 0;
long long total_time_v3 = 0, total_ops_v3 = 0;
// 进行多次试验取平均值
for (int t = 0; t < trials; ++t) {
// 生成随机物品
std::vector<Item> items(n);
for (int i = 0; i < n; ++i) {
items[i] = {weight_dist(gen), value_dist(gen), 0};
}
// 测试算法1的运行时间
auto start_v1 = std::chrono::high_resolution_clock::now();
complete_knapsack_v1(items, capacity);
auto end_v1 = std::chrono::high_resolution_clock::now();
total_time_v1 += std::chrono::duration_cast<std::chrono::microseconds>(end_v1 - start_v1).count();
total_ops_v1 += ops_count;
// 测试算法2的运行时间
auto start_v2 = std::chrono::high_resolution_clock::now();
complete_knapsack_v2(items, capacity);
auto end_v2 = std::chrono::high_resolution_clock::now();
total_time_v2 += std::chrono::duration_cast<std::chrono::microseconds>(end_v2 - start_v2).count();
total_ops_v2 += ops_count;
// 测试算法3的运行时间
auto start_v3 = std::chrono::high_resolution_clock::now();
complete_knapsack_v3(items, capacity);
auto end_v3 = std::chrono::high_resolution_clock::now();
total_time_v3 += std::chrono::duration_cast<std::chrono::microseconds>(end_v3 - start_v3).count();
total_ops_v3 += ops_count;
}
// 输出每个算法的平均结果
std::cout << n << ",v1," << total_time_v1 / trials << "," << total_ops_v1 / trials << "\n";
std::cout << n << ",v2," << total_time_v2 / trials << "," << total_ops_v2 / trials << "\n";
std::cout << n << ",v3," << total_time_v3 / trials << "," << total_ops_v3 / trials << "\n";
}
}
int main(int argc, char* argv[]) {
// 实验参数:最小物品数、最大物品数、步长、每个物品数的试验次数、背包容量
// 为保持算法1的合理运行时间使用较小的容量和物品数量
int min_n = 5; // 最小物品数
int max_n = 25; // 最大物品数
int step_n = 5; // 物品数步长
int trials = 10; // 每个物品数的试验次数
int capacity = 100; // 背包容量
run_experiments(min_n, max_n, step_n, trials, capacity);
return 0;
}