排序后双指针贪心:每轮让最贵的纪念品与最便宜的凑组,凑不上就单独成组,交换论证保证组数最少,O(n log n)。
OJ: roj
题目 ID: 3553
难度:普及
标签:贪心双指针排序python
创建: 2026-10-02 07:08
更新: 2026-10-07 13:50
题目描述
给定每组价格之和的上界
输入:第 1 行
样例:
思路
排序后,设最便宜的未处理件为
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-02 07:12
# update_at: 2026-10-02 07:12
import sys
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
limit = next(data) # 每组价格之和的上界 w
n = next(data) # 纪念品件数
prices = sorted(next(data) for _ in range(n))
# 双指针贪心:最贵的必须和某个最便宜的搭(或独自成组),
# 因为它和任何更贵的搭都会浪费配额,只可能让组数变多。
groups = 0
lo, hi = 0, n - 1
while lo <= hi:
if lo < hi and prices[lo] + prices[hi] <= limit: # 最便宜的能陪最贵的
lo += 1
hi -= 1
groups += 1 # prices[hi] 处理完毕:要么成组,要么落单
print(groups)
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 13:42
* update_at: 2026-10-06 13:42
*/
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 30005;
ll w; // 每组价格之和的上界
int n; // 纪念品件数
ll p[MAXN]; // 各纪念品价格
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> w;
cin >> n;
for (int i = 0; i < n; ++i) cin >> p[i];
sort(p, p + n); // 升序排序
int lo = 0, hi = n - 1;
int groups = 0;
while (lo <= hi) {
if (lo < hi && p[lo] + p[hi] <= w) // 最便宜的能陪最贵的
++lo; // 配对成功,lo 前进
--hi; // hi 每轮都处理掉
++groups;
}
cout << groups << '\n';
return 0;
}