题解:洛谷 P2945 Sand Castle

【题目来源】

洛谷:P2945 [USACO09MAR] Sand Castle S - 洛谷

【题目描述】

农夫 John 建造了一座沙堡!像所有好的城堡一样,城墙上有垛口,那种由垛口(空隙)和垛堞(填充空间)组成的精巧图案;见下图。他的城堡墙上的 N(1 <= N <= 25,000)个垛堞被方便地编号为 1 到 N;垛堞 i 的高度为 \(M_i\)(1 <= \(M_i\) <= 100,000);他的垛堞高度常常不同,这与许多其他的不同。

他希望以以下方式修改城堡设计:他有一个从 \(B_1\)\(B_N\)(1 <= \(B_i\) <= 100,000)的数字列表,并希望将垛堞的高度更改为这些高度 \(B_1, ..., B_N\) 的某种顺序(不一定是给定的顺序或从数据派生的任何其他顺序)。

为此,他雇佣了一些牛工匠来增加和降低垛堞的高度。当然,工匠们要价很高。特别是,他们向 FJ 收取总共 \(X\)(1 <= \(X\) <= 100)每单位高度增加的钱和 \(Y\)(1 <= \(Y\) <= 100)每单位高度减少的钱。

FJ 想知道如果他选择最佳的高度排列,修改他的沙堡的最低可能成本是多少。答案保证适合 32 位有符号整数。

注意:大约 40% 的测试数据将有 N <= 9,大约 60% 将有 N <= 18。

【输入】

* 第 1 行:三个用空格分隔的整数:N, X 和 Y

* 第 2 行到第 N+1 行:第 i+1 行包含两个用空格分隔的整数:\(M_i\)\(B_i\)

【输出】

* 第 1 行:一个整数,重建城堡所需的最低成本

【输入样例】

3 6 5
3 1
1 2
1 2

【输出样例】

11

【核心思想】

  1. 问题分析:给定 \(N\) 个垛堞的当前高度 \(M_i\) 和目标高度集合 \(B_i\)(可任意排列),增加单位高度花费 \(X\),降低单位高度花费 \(Y\)。求将垛堞高度修改为 \(B\) 的某种排列后的最小总成本。这是一个贪心匹配问题,关键在于发现将 \(M\)\(B\) 分别排序后按顺序一一匹配可使总成本最小。

  2. 算法选择

    • 排序后贪心匹配:将当前高度数组 \(M\) 和目标高度数组 \(B\) 分别升序排序,然后按位置 \(i\) 一一对应匹配
    • 成本计算:对每个位置,若 \(M_i < B_i\) 则增加,成本为 \((B_i - M_i) \times X\);否则降低,成本为 \((M_i - B_i) \times Y\)
  3. 关键步骤

    • 读取输入\(N, X, Y\)\(N\)\((M_i, B_i)\)
    • 分离数组:将 \(M_i\) 存入 \(M[1..N]\)\(B_i\) 存入 \(B[1..N]\)
    • 排序sort(M+1, M+N+1)sort(B+1, B+N+1)
    • 计算成本\(i\)\(1\)\(N\)):
      • \(M_i < B_i\)\(sum \mathrel{+}= (B_i - M_i) \times X\)
      • 否则:\(sum \mathrel{+}= (M_i - B_i) \times Y\)
    • 输出 \(sum\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \log N)\),排序主导
    • 空间复杂度:\(O(N)\),存储两个高度数组
  5. 贪心匹配的核心思想

    • 重排不等式:对于两组数,顺序配对(同为升序或降序)的差的绝对值之和最小,逆序配对最大。本题是重排不等式的推广(带权差的和最小化)
    • 单调性保持:将最小的当前高度匹配到最小的目标高度,避免"大跨度调整"带来的高额成本
    • 独立成本累加:每个垛堞的调整成本独立计算,总成本为各位置成本之和,排序匹配保证全局最优
    • 适用于"两组数配对 + 差值成本最小化"类问题,核心是通过排序实现最优匹配

【解题思路】

【算法标签】

普及- #贪心

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int n, x, y;
long long sum=0;
int m[100005],b[100005];
int main()
{
    cin >> n >> x >> y;  // 输入n、x和y
    for (int i=1; i<=n; i++) {  // 遍历n行数据
        cin >> m[i] >> b[i];  // 记录高度和预期高度
    }
    sort(m+1, m+n+1);  // 高度按照从小到大排序
    sort(b+1, b+n+1);  // 预期高度也按照从小到大排序
    for (int i=1; i<=n; i++) {  // 依次遍历n个齿轮
        if (m[i]<b[i]) {  // 如果高度小于预期高度
            sum += 1ll*(b[i]-m[i])*x;  // 需要提高高度
        } else {  // 否则
            sum += 1ll*(m[i]-b[i])*y;  // 需要降低高度
        }
    }
    cout << sum << endl;  // 输出结果
    return 0;
}

【运行结果】

3 6 5
3 1
1 2
1 2
11
posted @ 2026-08-28 15:55  团爸讲算法  阅读(7)  评论(0)    收藏  举报