Skip to content

最小代价问题

问题描述

给定一个数组 a,每个元素的值代表当前的数字,数组中的第i个数加1的代价是 b[i]。你需要找出最小的代价,使得数组a中的所有元素都各不相同.

image.png

思路

优先队列+贪心

例如:a={1,1,1,1,1} b={1,2,3,4,5}

通过把a变为{2,2,2,2,1}->{3,3,3,2,1}->{4,4,3,2,1}->{5,4,3,2,1}

用优先队列维护相同元素加1的代价最大值,这个代价最大值对应的a[i]的不动,其他相同元素都加1,ans加上使元素不同的最小代价

代码实现

c++
int solution(int n, std::vector<int> a, std::vector<int> b) {

  vector<pair<int, int>> arr;
  for (int i = 0; i < n; i++) {
    arr.push_back({a[i], b[i]});
  }

  //按a[i]从小到大排序
  sort(arr.begin(), arr.end());

  //优先队列维护a[i]相同下的b[i]
  priority_queue<int, vector<int>, less<int>> q;

  // sum是当前去掉相同元素的代价,tot是当前数字
  int sum = 0, tot = arr[0].first, ans = 0;
  int i = 0;
  while (!(i >= n && q.empty())) {

    //维护所有a中相同tot的优先队列
    while (i < n && arr[i].first == tot) {
      q.push(arr[i].second);
      sum += arr[i].second;
      i++;
    }

    //减去堆顶值
    if (!q.empty()) {
      sum -= q.top();
      ans += sum;
      q.pop();
    }

    //当前值加一
    tot++;
  }

  return ans;
}

(补充)优先队列

普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。

在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。

定义:priority_queue<Type, Container, Functional>

c++
1 //升序队列,小顶堆
2 priority_queue <int,vector<int>,greater<int> > q;
3 //降序队列,大顶堆
4 priority_queue <int,vector<int>,less<int> >q;
5 
6 //greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)


//自定义比较
auto cmp = [&nums1, &nums2](const pair<int, int> & a, const pair<int, int> & b) {
    return nums1[a.first] + nums2[a.second] > nums1[b.first] + nums2[b.second];
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> pq(cmp);

Released under the MIT License.