1 条题解

  • 0
    @ 2025-5-6 3:08:48

    解题思路:

    本题要求将参赛者分成两队,使得两队人数差不超过1,且总重量尽可能接近。通过动态规划的方法,将问题转化为“限定人数下的背包问题”,寻找最优分配方案。

    关键步骤:

    1. 总重量计算:计算所有人体重的总和,确定目标为寻找最接近总和一半的重量。
    2. 动态规划定义:定义 dp[j][k]dp[j][k] 表示选 jj 个人是否能组成总重量 kk
    3. 状态转移:遍历每个人,更新可能的选人数量 jj 和对应重量 kk,标记可达状态。
    4. 寻找最优解:在允许的最大人数范围内(n+1)/2(n+1)/2,从总和的一半开始向下查找最大的可行重量。
    5. 结果输出:确保输出时较小值在前,较大值在后。

    实现细节:

    • 人数限制处理:通过 (n+1)/2(n+1)/2 控制两队人数差不超过11
    • 动态规划优化:遍历顺序确保状态更新正确,避免重复计算。
    • 目标范围剪枝:仅搜索 00sum/2sum/2 的重量范围,缩小计算规模。

    特殊情况处理:

    • n=1n=1 时,直接输出该人体重和00
    • 当总重量为奇数时,优先选择接近较大值的一侧。

    C++实现:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    int n, sum;
    int a[500];            // 存储每个参赛者的体重
    int dp[110][110 * 500];// dp[j][k]表示选j个人是否能组成总重量k
    
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            sum += a[i];   // 计算总重量
        }
    
        // 初始化:选0个人组成0重量的状态为可行
        for (int j = 0; j <= (n + 1) / 2; j++) dp[j][0] = 1;
    
        // 动态规划状态转移
        for (int i = 1; i <= n; i++) {           // 遍历每个参赛者
            for (int j = (n + 1) / 2; j >= 1; j--) {    // 逆序处理人数,防止重复选人
                for (int k = sum / 2; k >= a[i]; k--) { // 遍历可能的重量
                    if (dp[j - 1][k - a[i]]) {          // 若前一步状态可达
                        dp[j][k] = 1;                   // 标记当前状态可达
                    }
                }
            }
        }
    
        // 寻找最大可行重量
        int ans = sum / 2;
        while (ans >= 0) {
            if (n % 2 == 0 && dp[n / 2][ans]) break;    // 偶数人数需选n/2人
            if (n % 2 == 1 && (dp[(n + 1) / 2][ans] || dp[n / 2][ans])) break; // 奇数人数允许两种人数
            ans--;
        }
    
        int ansmin = sum - ans;
        if (ansmin < ans) swap(ansmin, ans); // 确保较小值在前
        printf("%d %d\n", sum - ansmin, ansmin);
        return 0;
    }
    
    • 1

    信息

    ID
    1577
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者