题目链接
这类题目显然是邻项交换,但是有要注意的点。
先用邻项交换的方法跑一边,发现(cmp)函数为:(x.a+max(x.b,y.a)+y.b < y.a+max(y.b,x.a)+x.b)
其实可以化简:(min(x.a,y.b)<min(x.b,y.a))(因为(max(x,y)-x-y=-min(x,y)))
但是这是一个错的排序方式,所以说这个证明及其完全我就不写了
我感性理解了一下,就是化简后有(max,min)函数之类的好像都不行。
网上很多人说这个式子没有传递性,实际上这个式子不满足不可比的传递性。
而这个传递性可以理解成三个元素(a,b,c)对于某个不等关系满足(a=b,b=cRightarrow a=c)。(这是个不完全的理解,但暂时可以这么理解,泛用性应该还不差)
实际上,我们这样带有(max,min)函数的式子一般不满足,拿此题来说对于以下的三个产品就不满足:
7 3
1 1
1 6
至此我们先强调一点,我并没有说(Johnson)算法是错的,实际上从原理上来说,这个要求是完全正确,也就是说,我们的最优排序方案一定满足这个式子,用这个式子人工排序也一定能成,但是在计算机中行,因为sort的排序方式是一定会满足不可比的传递性,也就是说两个数相等对其顺序没有影响,但是这种排序方式不一定,所以我们要将其转化,化为满足不可比的传递性的形式。
换句话说,我们要找到一种等价的比较方式,使的无论什么情况下均满足上面的式子且具有不可比的传递性。
转换的时候实际上我们并不是说完全抛弃掉原来的方式,观察(Hack)样例,实际上就是当有(a_i==b_i)时会出锅。
也就是说,我们将这种情况单独领出来考虑即可:
- (a_i<b_i&&a_j=b_j)时不用交换(分类讨论)
- (a_i>b_i&&a_j=b_j)时需要交换(分类讨论)
所以我们得到了如下的分类(每一类的顺序即为其优先级):
- (a_i<b_i&&a_j<b_j),这时可以用(min(x.a,y.b)<min(x.b,y.a))(或者你可以说按照(a_i<a_j)排序,因为你分类讨论之后发现这两者一样)
- (a_i=b_i),这时随意(自行讨论)。
- (a_i>b_i&&a_j>b_j),这时可以用(min(x.a,y.b)<min(x.b,y.a))(或者你可以说按照(b_i>b_j)排序,因为你分类讨论之后发现这两者一样)
这时我们就可以写了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int f=1,w=0;char x=0;
while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
return w*f;
}
const int N=20010;
int n,f[N];
struct Person
{
int x,y,d,id;
bool operator < (const Person &b)
{
return d==b.d?min(x,b.y)<min(y,b.x):d<b.d;
}
}p[N];
main(){
#ifndef ONLINE_JUDGE
freopen("A.in","r",stdin);
#endif
n=read();
for(int i=1;i<=n;i++) p[i].x=read(),p[i].id=i;
for(int i=1;i<=n;i++)
{
p[i].y=read();
p[i].d=p[i].x<p[i].y?-1:p[i].x>p[i].y?1:0;
}
sort(p+1,p+n+1);
int Ta=p[1].x,Tb=p[1].x+p[1].y;
for(int i=2;i<=n;i++) Tb=max(Ta+p[i].x,Tb)+p[i].y,Ta+=p[i].x;
printf("%lld
",Tb);
for(int i=1;i<=n;i++) printf("%lld ",p[i].id);
}
其实还有一种做法:我们发现(Tb=max(Ta+p[i].x,Tb)+p[i].y,Ta+=p[i].x;)是我们求答案的过程。
就是(懒得打了)
没错,就是皇后游戏,观察全局,发现和(a_i)的大小有关,因此当我们判到(min(x.a,y.b)=min(x.b,y.a))时,可以按照(a_i<a_j)的顺序排序(应该本质上是一样的,只是这样更好理解。)
皇后游戏的代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int f=1,w=0;char x=0;
while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
return w*f;
}
const int N=20010;
int n,f[N];
struct Person
{
int x,y;
bool operator < (const Person &b)
{
return min(x,b.y)==min(y,b.x)?x<b.x:min(x,b.y)<min(y,b.x);
}
}p[N];
main(){
#ifndef ONLINE_JUDGE
freopen("A.in","r",stdin);
#endif
int T=read();
while(T--)
{
int Tot=0,ans=0;n=read();
for(int i=1;i<=n;i++) p[i].x=read(),p[i].y=read();
sort(p+1,p+n+1);
for(int i=1;i<=n;i++)
Tot+=p[i].x,ans=max(ans,Tot)+p[i].y;
printf("%lld
",ans);
}
}