试题 D:平均
贪心
将每一组输入看作一对 pair
,用数组 nums
记录每个数出现的次数,同时由输入 n
可以得到每个数应该出现的次数 cnt = n/10
。
算法思路
- 按照 b i b_i bi 的大小降序排列
- 从前往后遍历,如果数字
i
出现的次数nums[i] < cnt
,那么nums[i]++
;反之ans += b[i]
- 输出
ans
此题贪心的策略是代价高的且出现次数未达目标的 pair
不会被修改,这样修改的都是代价较低的 pair
。可以证明这样的策略可以得到最优解。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
vector<pair<int, long>> vec(n);
vector<int> nums(n, 0);
for (int i = 0; i < n; i++)
{
cin >> vec[i].first >> vec[i].second;
}
// 按照代价从高到低排序
sort(vec.begin(), vec.end(), [](pair<int, long> a, pair<int, long> b)
{ return b.second < a.second; });
long ans = 0;
int cnt = n / 10; // 每个数出现的次数
for (int i = 0; i < n; i++)
{
// 如果当前数的次数小于cnt,那么就将当前数的次数加1
if (nums[vec[i].first] < cnt)
{
nums[vec[i].first]++;
}
else
{
ans += vec[i].second;
}
}
cout << ans << endl;
return 0;
}