[浅谈] 邻项交换排序贪心

\(\color{darkblue}\text{参考文献}\)

浅谈邻项交换排序的应用以及需要注意的问题

\(\color{darkblue}\text{总结}\)

对于一些决定贪心顺序的题目,我们可以通过确定相邻两个人的排列关系来确定最优顺序。但是相邻最优推广到全局最优还需要证明两种关系:

  1. 可比传递性。 当 \(a_i<a_j\)\(a_j<a_k\) 时,还应当保证 \(a_i<a_k\)

  2. 不可比传递性,如果 \(a_i=a_j\)\(a_j=a_k\) ,还应当保证 \(a_i<=a_k\)

\(\color{darkblue}\text{例题}\)

\(\color{purple}\text{P1080 [NOIP2012 提高组] 国王游戏}\)

考虑相邻的人 \(P_1\)\(P_2\) ,设他们左右手分别为 \(a_i\)\(b_i\) ,设他们前面的人左手乘积为 \(t\)

如果 \(P_1\) 在前, \(ans=\max(\frac{t}{b_1},\frac{t\cdot a_1}{b_2})\)
\(P_2\) 在前同理, \(ans=\max(\frac{t}{b_2},\frac{t\cdot a_2}{b_1})\)

其实已经可以做了。但是这个式子仍能化简。\(\frac{t\cdot a_2}{b_1}>\frac{t}{b_1}\)\(\frac{t\cdot a_1}{b_2}>\frac{t}{b_2}\) ,所以可以变成比较 \(\frac{t\cdot a_2}{b_1}\)\(\frac{t\cdot a_1}{b_2}\)

最后,我讨厌高精度。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5010;
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
struct node{
	int a,b;
}e[N];
bool cmp(node t1,node t2){
	return t2.a*t2.b>t1.a*t1.b;
}
int n,A[N],B[N];
struct NUM{
	int len,num[10000010];	
}S1,S2,S3;
void add(int x){
	for(int i=1;i<=S1.len;i++)S1.num[i]*=x;
	for(int i=1;i<S1.len;i++){
		S1.num[i+1]+=S1.num[i]/10;
		S1.num[i]%=10;
	}
	while(S1.num[S1.len]>=10){
		S1.num[S1.len+1]+=S1.num[S1.len]/10;
		S1.num[S1.len]%=10;
		S1.len++;
	}
	return;
}
void del(int x){
	int tmp=0;
	S2.len=0;
	for(int i=S1.len;i>=1;i--){
		tmp=tmp*10+S1.num[i];
		if(tmp>=x){
			S2.len=max(S2.len,i);
			S2.num[i]=tmp/x;
			tmp%=x; 
		}
		else S2.num[i]=0; 
	}
	return;
}
bool gt(){
	if(S2.len!=S3.len)return S2.len>S3.len;
	for(int i=S2.len;i>=1;i--)
		if(S2.num[i]!=S3.num[i])
			return S2.num[i]>S3.num[i];
}
void rp(){
	S3.len=S2.len;
	for(int i=S3.len;i>=1;i--)
		S3.num[i]=S2.num[i];
	return;
}
signed main(){
	n=read();
	e[0].a=read(),e[0].b=read();
	for(int i=1;i<=n;i++)e[i].a=read(),e[i].b=read();
	sort(e+1,e+n+1,cmp);
	
	S1.len=1;S1.num[1]=1;
	for(int i=1;i<=n;i++){
		add(e[i-1].a);
		del(e[i].b);
		if(gt())rp();
	}
	for(int i=S3.len;i>=1;i--)
		printf("%lld",S3.num[i]);
	printf("\n");
	S1.len=1;S1.num[1]=1;
	return 0;
}

\(\color{purple}\text{P1248 加工生产调度}\)

本做法仅供参考,正确性无法保证。

那两个物品,编号为 \(1\)\(2\)
\(1\) 在前: \(ans=a_1+\max(a_2,b_1)+b_2\)
\(2\) 在前: \(ans=a_2+\max(a_1,b_2)+b_1\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
struct node{
	int a,b,id;
}e[N];
bool cmp(node t1,node t2){
	return min(t1.a,t2.b)<min(t2.a,t1.b);
}
int n,A[N],B[N];
int main(){
	n=read();
	for(int i=1;i<=n;i++)e[i].a=read();
	for(int i=1;i<=n;i++)e[i].b=read(),e[i].id=i;
	sort(e+1,e+n+1,cmp);
	for(int i=1;i<=n;i++){
		A[i]=A[i-1]+e[i].a;
		B[i]=max(B[i-1],A[i])+e[i].b;
	}
	printf("%d\n",B[n]);
	for(int i=1;i<=n;i++)
		printf("%d ",e[i].id);
	printf("\n");
	return 0;
}
posted @ 2023-04-23 21:42  FJOI  阅读(92)  评论(0)    收藏  举报