#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;
}
