当前位置:首页 > 洛谷 > 洛谷P1489题解析:动态规划求解血量分配问题的优化方案

洛谷P1489题解析:动态规划求解血量分配问题的优化方案

7个月前 (07-24)

洛谷P1489题解析:动态规划求解血量分配问题的优化方案 洛谷题解 动态规划 背包问题 01背包 第1张

一、题目解读

洛谷P1489题要求将n个人的血量分配为两组,使两组血量之差最小,同时人数尽可能平衡。这是一类典型的组合优化问题,需要高效算法找到最优解。题目难点在于如何在有限时间内计算所有可能的组合,并从中筛选出最优结果。

二、解题思路

采用动态规划(Dynamic Programming)解决该问题。核心思想是将原问题分解为子问题,利用子问题的最优解推导整体最优解。通过构建二维dp数组dp[i][j]表示“选i个人能否组成j血量”,逐步迭代求解,最终找到最接近总血量一半的分配方案,并兼顾人数平衡。

三、解题步骤

1. 数据预处理:输入n和每个人的血量,计算总血量total,初始化dp数组。

2. 动态规划迭代:外层循环遍历人数k,内层双循环倒序枚举人数i和血量j,利用状态转移方程dp[i+1][j] = dp[i][j-blood[k]]更新。

3. 最优解筛选:从dp数组中寻找最接近total/2的血量值,同时比较人数差,优先选择人数更平衡的方案。

4. 输出结果:输出两组血量的最小值和最大值。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); // 加快输入输出速度

    int n;
    cin >> n;
    vector<int> blood(n);
    int total = 0;
    
    for (int i = 0; i < n; ++i) {
        cin >> blood[i];
        total += blood[i];
    }

    // dp[i][j]表示选i个人能否组成j血量
    vector<vector<bool>> dp(n/2+2, vector<bool>(total/2+1, false));
    dp[0][0] = true; // 初始状态:不选人时血量为0

    for (int k = 0; k < n; ++k) {
        for (int i = min(k, n/2); i >= 0; --i) {
            for (int j = total/2; j >= blood[k]; --j) {
                if (dp[i][j-blood[k]]) { // 若存在前状态,更新当前状态
                    dp[i+1][j] = true;
                }
            }
        }
    }

    // 寻找最优解:最接近total/2且人数最平衡
    int best_sum = 0, best_count = 0;
    for (int j = total/2; j >= 0; --j) {
        for (int i = 0; i <= n/2; ++i) {
            if (dp[i][j]) {
                if (abs(total-2*j) < abs(total-2*best_sum)) {
                    best_sum = j;
                    best_count = i;
                } else if (abs(total-2*j) == abs(total-2*best_sum)) {
                    if (abs(n-2*i) < abs(n-2*best_count)) {
                        best_count = i;
                    }
                }
            }
        }
    }

    cout << min(best_sum, total-best_sum) << " " 
         << max(best_sum, total-best_sum) << endl;
    return 0;
}

五、总结

本文通过动态规划方法解决了洛谷P1489的血量分配问题,核心在于将复杂组合问题转化为状态转移方程,并通过优化迭代过程降低时间复杂度。代码中通过倒序循环避免重复计算,最优解筛选兼顾了血量差和人数平衡的双重要求,为同类背包问题提供了高效参考方案。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣70题:告别暴力递归!从零实现记忆化搜索解法

力扣70题:告别暴力递归!从零实现记忆化搜索解法

题意解析:想象你站在楼梯底部,面前有n级台阶。每次你可以选择跨1级或2级台阶,最终到达顶端的路径有多少种不同的走法?这个问题本质上是在探索分叉决策的叠加效果——当我们把每个台阶处的选择看作二叉树的分支...

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

题目重解我们面对一个经典背包问题的变体:给定n个物品,每个物品有重量w和价值v,背包容量为V。需要回答两个问题:1) 普通情况下能获得的最大价值;2) 必须恰好装满背包时的最大价值(若无法装满则输出0...

从零到一掌握背包问题:洛谷P1164题解精讲,附带优化

从零到一掌握背包问题:洛谷P1164题解精讲,附带优化

题目重解:小A带着m元钱来到餐馆,菜单上有n道菜,每道菜都有确定的价格。现在需要计算出刚好花完m元的点菜方案总数。这个问题看似简单,但当菜品数量增多时,暴力枚举就会变得不可行,需要更高效的算法来解决。...

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

一、题目解读CSP-J 2019年的“公交换乘”题目(洛谷P5661)要求模拟地铁与公交交替出行的费用计算。题目核心在于地铁消费会产生优惠券,而公交可在45分钟内使用优惠券抵扣车费。需要处理n条出行记...

牛客网288555题解题指南:动态规划求解小红的暑假(附代码解析)

牛客网288555题解题指南:动态规划求解小红的暑假(附代码解析)

一、题目解读牛客网288555题要求解决一个组合数学问题:有三位朋友,每天需邀请其中一位参加聚会,但不能连续两天邀请同一位朋友。给定天数n,求满足条件的不同邀请方案总数。题目考察动态规划、状态转移及组...

【蓝桥杯国赛A组】冰山体积计算:动态规划与map统计的解题方案(洛谷P8767)

【蓝桥杯国赛A组】冰山体积计算:动态规划与map统计的解题方案(洛谷P8767)

一、题目解读本题为2021年蓝桥杯国赛A组题目“冰山”(洛谷P8767),要求处理冰山在融化与新生成过程中的体积变化。每日存在两种操作:冰山体积按固定值x融化(体积不足x的部分视为完全融化),以及新增...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。