浅谈邻项交换法和反悔贪心

浅谈邻项交换法和反悔贪心

邻项交换法

对于 \(n\) 个多元组,需要按照顺序完成某种任务,且顺序可自行安排,就可通过邻项交换法确定最优顺序。

设元素为 \(a_i\),考虑 \(a_i\)\(a_{i+1}\)

\(a_i\)\(a_{i+1}\) 需要调换位置当且仅当 \(f(\left\{a_{i+1},a_i\right\})<f(\left\{a_i,a_{i+1}\right\})\)

其中 \(f\) 是估价函数,每道题都不一样,需要自行设计。

一般来说将上述式子化简完可以得到对于 \(n\) 元组内部的一种新的排序方式。

具体地到后面例题讲。

反悔贪心

有一类题不能保证按顺序取直到不能取的方法就是最优的,所以要在后面时考虑反悔。

大概是维护一个集合表示当前取了什么元素,以及一个最优值。

在遇到一个新元素 \(x\) 时,分两种情况:

  • 能取。那就笑纳。
  • 不能取,考虑已选取的集合内是否存在一个元素 \(y\),使得放弃 \(y\) 就能要 \(x\) 且最优值更优。如果是就放弃 \(y\),取 \(x\)。否则就什么都不做。

这样我们就可以在保证总体不劣的情况下使最优值尽可能优秀。

例题

考虑相邻的两场比赛 \(a_{i},a_{i+1}\),其中 \(a_i=\left\{x_i,l_i\right\}\)\(a_{i+1}\) 同理。

那么需要交换当且仅当原来是仅能参加 \(a_i\),不能参加 \(a_{i+1}\)

化成式子就是这样:

\[\sum_{j=1}^{i-1}x_j\le l_i\\ \sum_{j=1}^{i-1}x_j+x_i>l_{i+1} \]

\(S=\sum_{j=1}^{i-1} x_j\)。那么式子就变为:

\[S\le l_i\\ S+x_i>l_{i+1} \]

然后交换后更优就是都能参加,式子:

\[S\le l_{i+1}\\ S+x_{i+1}\le l_i \]

发现若 \(S+x_{i+1}\le l_i\),必有 \(S\le l_i\),所以删掉 \(S\le l_i\)

然后把所有式子的 \(S\) 单独拎到一边,有:

\[l_{i+1}-x_i<S\\ S\le l_{i+1}\\ S\le l_{i}-x_{i+1} \]

对于第二个式子,注意到:\(l_{i+1}-x_i<S\le \min\{l_{i+1},l_i-x_{i+1}\}\),发现 \(l_{i+1}-x_i\) 必定小于 \(l_{i+1}\),所以可以不考虑第二个式子。

注意到剩下 \(l_{i+1}-x_i<l_i-x_{i+1}\),移项,有 \(l_{i+1}+x_{i+1}<l_i+x_i\)

所以只要按照 \(l_i+x_i\) 从小到大排序即可。

然后注意我们只确定了选择的顺序,没有确定选哪些,所以要用到反悔贪心。

维护当前选了什么和选了几个。

那么遇到不能选的比赛肯定是尽可能使当前等级降低并参加。

那么降低等级就是返回之前选过 \(x_i\) 最大的比赛。

这可以用大根堆维护。

于是就做完了,时间复杂度 \(O(n\log n)\)

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ljl;
const int N=5e5+5;
int n;
ljl cur;
priority_queue<ljl> pq;
struct NODE{
	ljl x,l;
	bool operator < (const NODE a)const{
		return x+l<a.x+a.l; 
	}
}node[N];

int main(){
	ios::sync_with_stdio(0);
	cin>>n;
	for(int i=1;i<=n;++i)cin>>node[i].x;
	for(int i=1;i<=n;++i)cin>>node[i].l;
	sort(node+1,node+n+1);
	for(int i=1;i<=n;++i)
	{
		if(cur<=node[i].l)
		{
			cur+=node[i].x;
			pq.push(node[i].x);
		}
		else
		{
			if(cur-pq.top()<=node[i].l&&node[i].x<pq.top())
			{
                //注意上面判断其实只需要node[i].x<pq.top()就行了,第一个条件可以推式子知道是一定满足的
				cur-=pq.top();
				pq.pop();pq.push(node[i].x);
				cur+=node[i].x; 
			}
		}
	}cout<<(int)pq.size()<<'\n';
	return 0;
}

posted @ 2026-08-25 11:03  Atserckcn  阅读(12)  评论(0)    收藏  举报