#include #include #include #include #include #include struct Item { int weight; // 物品重量 int value; // 物品价值 int count; // 物品数量(用于多重背包问题) }; // 全局操作计数器,用于性能分析 long long ops_count = 0; // ================================================================= // 完全背包问题算法实现 // ================================================================= // 算法1:朴素动态规划(三层循环) int complete_knapsack_v1(const std::vector& items, int capacity) { ops_count = 0; // 重置操作计数器 int n = items.size(); if (n == 0) return 0; std::vector> dp(n + 1, std::vector(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& items, int capacity) { ops_count = 0; // 重置操作计数器 int n = items.size(); if (n == 0) return 0; std::vector> dp(n + 1, std::vector(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& items, int capacity) { ops_count = 0; // 重置操作计数器 std::vector 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 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(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(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(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; }