题解:洛谷 P11960 平均分配

【题目来源】

洛谷:P11960 [GESP202503 五级] 平均分配 - 洛谷(luogu.com.cn)

【题目描述】

小 A 有 \(2n\) 件物品,小 B 和小 C 想从小 A 手上买走这些物品。对于第 \(i\) 件物品,小 B 会以 \(b_i\) 的价格购买,而小 C 会以 \(c_i\) 的价格购买。为了平均分配这 \(2n\) 件物品,小 A 决定小 B 和小 C 各自只能买走恰好 \(n\) 件物品。你能帮小 A 求出他卖出这 \(2n\) 件物品所能获得的最大收入吗?

【输入】

第一行,一个正整数 \(n\)

第二行,\(2n\) 个整数 \(b_1,b_2,…,b_{2n}\)

第三行,\(2n\) 个整数 \(c_1,c_2,…,c_{2n}\)

【输出】

一行,一个整数,表示答案。

【输入样例】

3
1 3 5 6 8 10
2 4 6 7 9 11

【输出样例】

36

【核心思想】

  1. 问题分析:给定 \(2n\) 件物品,每件物品有小 B 的购买价 \(b_i\) 和小 C 的购买价 \(c_i\)。要求小 B 和小 C 各买恰好 \(n\) 件,最大化总收入。这是一个排序 + 贪心分配问题,关键在于按 \(b_i - c_i\) 的差值排序,差值大的优先分配给 B,差值小的优先分配给 C。

  2. 算法选择

    • 差值排序:按 \(b_i - c_i\) 降序排列,将每件物品的" B 相对优势"量化
    • 贪心分配:前 \(n\) 件给 B(差值大,B 出价远高于 C),后 \(n\) 件给 C(差值小甚至负,C 出价更高或接近)
  3. 关键步骤

    • 读入数据\(n\),数组 \(b[1..2n]\)\(c[1..2n]\)
    • 计算差值:对每件物品 \(i\),计算 diff = b[i] - c[i]
    • 降序排序:按 diff 从大到小排序
    • 贪心累加
      • \(n\) 件:ans += b[i](分配给 B)
      • \(n\) 件:ans += c[i](分配给 C)
    • 输出 ans
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \log n)\),排序 \(O(n \log n)\),累加 \(O(n)\)
    • 空间复杂度:\(O(n)\),存储结构体数组
  5. 差值排序贪心分配的核心思想

    • 边际收益分析:将物品 \(i\) 分配给 B 而非 C 的边际收益为 \(b_i - c_i\)。差值越大,分配给 B 的收益越高
    • 排序创造单调性:按差值降序后,前 \(n\) 件是"最适合给 B"的物品,后 \(n\) 件是"最适合给 C"的物品
    • 交换论证:若最优解中存在差值 \(d_i < d_j\)\(i\) 给 B、\(j\) 给 C 的情况,交换两者分配可使总收入增加 \(d_j - d_i > 0\),矛盾。故排序后的分配为最优
    • 约束满足:排序后前 \(n\) 件和后 \(n\) 件天然满足"各 \(n\) 件"的数量约束
    • 适用于"两组各选 \(n\) 个、最大化总和"的分配问题,核心在于将分配决策转化为排序后的前缀/后缀选取

【算法标签】

普及 #贪心

【代码详解】

#include <bits/stdc++.h>
using namespace std;

#define int long long  // 定义宏,将int替换为long long类型
const int N = 100005;  // 定义数组的最大大小

int n;                 // 输入的n值
int b[2*N], c[2*N];    // 存储输入的b数组和c数组

// 定义结构体,存储b值、c值和它们的差值
struct node {
    int b, c, diff;    // b值,c值,b-c的差值
} a[2*N];              // 结构体数组

// 自定义排序函数,按差值从大到小排序
bool cmp(node x, node y) {
    return x.diff > y.diff;
}

signed main() {  // 使用signed代替int,因为宏定义了int为long long
    cin >> n;    // 输入n

    // 输入b数组和c数组
    for (int i = 1; i <= 2 * n; i++)
        cin >> b[i];
    for (int i = 1; i <= 2 * n; i++)
        cin >> c[i];

    // 初始化结构体数组,计算每个元素的差值
    for (int i = 1; i <= 2 * n; i++)
        a[i] = {b[i], c[i], b[i] - c[i]};

    // 对结构体数组按差值从大到小排序
    sort(a + 1, a + 2 * n + 1, cmp);

    int ans = 0;  // 初始化结果为0

    // 前n个元素取b值
    for (int i = 1; i <= n; i++)
        ans += a[i].b;

    // 后n个元素取c值
    for (int i = n + 1; i <= 2 * n; i++)
        ans += a[i].c;

    // 输出最终结果
    cout << ans << endl;

    return 0;
}

【运行结果】

3
1 3 5 6 8 10
2 4 6 7 9 11
36
posted @ 2026-08-10 12:25  团爸讲算法  阅读(27)  评论(0)    收藏  举报