临项交换法在贪心算法中的应用
1.排序不等式的证明
我们给出一个高中常见的排序不等式:
对 \(a_1\leq a_2\leq ...... \leq a_n\) 且 \(b_1 \leq b_2 \leq ...... \leq b_n\),
设\(a_{t_1},a_{t_2}, ...... ,a_{t_{n-1}},a_{t_n}\)是数列\(\left\{ a_n \right\}\)的一个随机排列,
那么有如下不等式成立:
即 逆序和 \(\leq\) 乱序和 \(\leq\) 顺序和
其证明可以通过 临项交换法 进行:
对于顺序和,随机挑选\(i,j(i<j)\)两项进行交换,即将\(a_ib_i+a_jb_j\)交换为\(a_ib_j+a_jb_i\)。
那么
可以说明对于顺序和,任意选择两项进行交换都不会使得值更大
将其进行推广,可以得出顺序和最大
同理,对于逆序和,任意选择两项交换都不会使得值更小,推广后得到逆序和最小
这样我们便证明了上述结论
上述证明的核心在于 临项交换法:对一个按某种顺序排列的序列,证明任意两项交换后都不会使得答案更优,则该顺序排列是最优解,或者说,当两项按某种顺序排列后最优,大概率可以推广到\(n\)项。这种方法常常用于以排序为基础的贪心题的证明。
2.临项交换在贪心法中的应用——NOIP2012 国王游戏
本来这个题目是蓝题的,结果因为太经典,做的人太多,已经变成绿题了就离谱
思路
记皇帝是第0个人,第\(i\)个人所得金币数量为\(v_i\),那么有
我们的目标是使得\(ans=max\left\{ v_1,v_2,......,v_n \right\}\)最小
临项交换:我们先按某种方式进行排序,随后随意抽取相邻两项\((i,i+1)\)尝试交换。
原本答案为\(ans=max(ans0,\frac{\prod_{k=0}^{i-1}a_k}{b_i},\frac{\prod_{k=0}^{i}a_k}{b_{i+1}})\)
交换后变为\(ans=max(ans0,\frac{\prod_{k=0}^{i-1}a_k}{b_{i+1}},\frac{(\prod_{k=0}^{i-1}a_k)*a_{k+1}}{b_i})\)
那么我们比较一下\(\frac{\prod_{k=0}^{i}a_k}{b_{i+1}}\)和\(\frac{(\prod_{k=0}^{i-1}a_k)*a_{k+1}}{b_i}\)的大小即可
约去公因式,即比较\(\frac{a_k}{b_{i+1}}\)和\(\frac{a_{i+1}}{b_i}\)即可
当\(a_ib_i\leq a_{i+1}b_{i+1}\)时,此时\(ans1\)不会大于\(ans2\),无需交换,否则交换后可以使答案不会变差(甚至变优)
那么我们就得到了一个排序思路:以\(a_ib_i\)作为排序依据,从小到大排序即可
代码
略,洛谷题解挺多的了(这题好像还要写一下高精度才能完全AC)
补充题目
可以看下我前面写的博客
临项交换法:把\(n\)个数字按照字符串读入,按某一顺序排列,尝试将相邻两项\((a,b)\)进行交换,可以发现当\(a+b\geq b+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;
}