查看: 54|回复: 0

洛谷P1489题解:动态规划解决分队问题

[复制链接]
  • TA的每日心情
    擦汗
    2025-8-14 14:38
  • 签到天数: 54 天

    [LV.5]常住居民I

    53

    主题

    0

    回帖

    91

    积分

    注册会员

    Rank: 2

    积分
    91
    发表于 2025-8-6 09:36:56 | 显示全部楼层 |阅读模式
    一、问题分析
    题目要求将n个人分成两队,使得两队总血量尽可能接近,同时两队人数也要尽可能平衡。这是一个典型的分组优化问题,可以使用动态规划高效解决。
    二、算法核心思路
    • 动态规划定义

      • dp[j]表示选i个人能否组成j血量
      • 采用三维降维优化,节省空间复杂度


      • 逆序更新避免重复计算
      • 三重循环分别处理:人员、人数、血量

    • 最优解搜索

      • 寻找最接近总血量一半的组合
      • 同时考虑人数平衡的优化

    三、完整代码实现(带注释)
    1. #include <iostream>
    2. #include <vector>
    3. #include <algorithm>
    4. using namespace std;

    5. int main() {
    6.     ios::sync_with_stdio(false);  // 加速输入输出
    7.     cin.tie(nullptr);             // 解除cin与cout的绑定
    8.    
    9.     int n;
    10.     cin >> n;
    11.     vector<int> blood(n);
    12.     int total = 0;
    13.    
    14.     for (int i = 0; i < n; ++i) {
    15.         cin >> blood[i];
    16.         total += blood[i];
    17.     }

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

    21.     for (int k = 0; k < n; ++k) {
    22.         for (int i = min(k, n/2); i >= 0; --i) {
    23.             for (int j = total/2; j >= blood[k]; --j) {
    24.                 if (dp[i][j-blood[k]]) {
    25.                     dp[i+1][j] = true;
    26.                 }
    27.             }
    28.         }
    29.     }

    30.     // 寻找最优解:最接近total/2且人数最平衡
    31.     int best_sum = 0, best_count = 0;
    32.     for (int j = total/2; j >= 0; --j) {
    33.         for (int i = 0; i <= n/2; ++i) {
    34.             if (dp[i][j]) {
    35.                 if (abs(total-2*j) < abs(total-2*best_sum)) {
    36.                     best_sum = j;
    37.                     best_count = i;
    38.                 } else if (abs(total-2*j) == abs(total-2*best_sum)) {
    39.                     if (abs(n-2*i) < abs(n-2*best_count)) {
    40.                         best_count = i;
    41.                     }
    42.                 }
    43.             }
    44.         }
    45.     }

    46.     cout << min(best_sum, total-best_sum) << " "
    47.          << max(best_sum, total-best_sum) << endl;
    48.     return 0;
    49. }
    复制代码


    四、调试技巧
    • 使用小规模测试数据验证
    • 打印中间状态检查
    • 检查状态转移是否正确

    参考:洛谷P1489题解:动态规划解决分队问题

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表