临项交换法在贪心算法中的应用

1.排序不等式的证明

我们给出一个高中常见的排序不等式:

a1a2......anb1b2......bn

at1,at2,......,atn1,atn是数列{an}的一个随机排列,

那么有如下不等式成立:

anb1+an1b2+......+anb1at1b1+at2b2+......+atnbna1b1+a2b2+......+anbn

即 逆序和 乱序和 顺序和

其证明可以通过 临项交换法 进行:

对于顺序和,随机挑选i,j(i<j)两项进行交换,即将aibi+ajbj交换为aibj+ajbi

那么

(aibi+ajbj)(aibj+ajbi)=(ajai)(bjbi)0

可以说明对于顺序和,任意选择两项进行交换都不会使得值更大

将其进行推广,可以得出顺序和最大

同理,对于逆序和,任意选择两项交换都不会使得值更小,推广后得到逆序和最小

这样我们便证明了上述结论

上述证明的核心在于 临项交换法:对一个按某种顺序排列的序列,证明任意两项交换后都不会使得答案更优,则该顺序排列是最优解,或者说,当两项按某种顺序排列后最优,大概率可以推广到n项。这种方法常常用于以排序为基础的贪心题的证明。

2.临项交换在贪心法中的应用——NOIP2012 国王游戏

链接

本来这个题目是蓝题的,结果因为太经典,做的人太多,已经变成绿题了就离谱

思路

记皇帝是第0个人,第i个人所得金币数量为vi,那么有

vi=k=0i1akbi

我们的目标是使得ans=max{v1,v2,......,vn}最小

临项交换:我们先按某种方式进行排序,随后随意抽取相邻两项(i,i+1)尝试交换。

原本答案为ans=max(ans0,k=0i1akbi,k=0iakbi+1)

交换后变为ans=max(ans0,k=0i1akbi+1,(k=0i1ak)ak+1bi)

那么我们比较一下k=0iakbi+1(k=0i1ak)ak+1bi的大小即可

约去公因式,即比较akbi+1ai+1bi即可

aibiai+1bi+1时,此时ans1不会大于ans2,无需交换,否则交换后可以使答案不会变差(甚至变优)

那么我们就得到了一个排序思路:以aibi作为排序依据,从小到大排序即可

代码

略,洛谷题解挺多的了(这题好像还要写一下高精度才能完全AC)

补充题目

1.2019年河海ACM选拔赛低年级组H题 刷题狂魔

可以看下我前面写的博客

2.洛谷P1012 拼数

临项交换法:把n个数字按照字符串读入,按某一顺序排列,尝试将相邻两项(a,b)进行交换,可以发现当a+bb+a(注意,这里时按照字符串方式进行加减,类似于拼接,而不是算术加法)时无需交换,反之交换后可以使得答案更优。代码如下:

#include<bits/stdc++.h> using namespace std; string a[21]; bool cmp(string a,string b){ return a+b>b+a; } int main() { int n; cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++)cout<<a[i]; return 0; }

__EOF__

本文作者cyhforlight
本文链接https://www.cnblogs.com/cyhforlight/p/14176308.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   cyhforlight  阅读(575)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示