邻项交换排序

Posted cindy-chan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了邻项交换排序相关的知识,希望对你有一定的参考价值。

邻项交换排序

通过找到 决定 相邻两个单位位置 的策略 以推广到整个队伍,是一种通过贪心解决问题的方法。

题目大意

有n个大臣,第i位大臣左手的数为ai?,右手的数为bi?,且ai?bi?均为正整数。他能获得的数ci?由以下关系给出: 

技术图片

ci?最大的大臣的ci?最小为多少。

输入输出格式

输入格式:

第一行包含一个正整数 T,表示测试数据的组数。

接下来 T 个部分,每个部分的第一行包含一个正整数 n,表示大臣的数目。

每个部分接下来 n 行中,每行两个正整数,分别为 ai和 bi,含义如上文所述。

 

输出格式:

共 T 行,每行包含一个整数,表示获得奖金最多的大臣所获得的奖金数目。

输入输出样例

输入样例#1: 
1
3
4 1
2 2
1 2
输出样例#1: 
8
输入样例#2:
2
5
85 100
95 99
76 87
60 97
79 85
12
9 68
18 45
52 61
39 83
63 67
45 99
52 54
82 100
23 54
99 94
63 100
52 68
输出样例#2: 
528
902

说明

按照 1、2、3 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 10;

按照 1、3、2 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 9;

按照 2、1、3 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 9;

按照 2、3、1 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 8;

按照 3、1、2 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 9;

按照 3、2、1 这样排列队伍,获得最多奖金的大臣获得奖金的数目为 8。

当按照 3、2、1 这样排列队伍时,三位大臣左右手的数分别为:

(1, 2)、(2, 2)、(4, 1)

第 1 位大臣获得的奖金为 1 + 2 = 3;

第 2 位大臣获得的奖金为 max3, 3 + 2 = 5;

第 3 为大臣获得的奖金为 max5, 7 + 1 = 8。

对于全部测试数据满足:T10, 1n20 000,1ai?,bi?109

分析

Part 1

我们要找大臣的顺序,且排列顺序没有后效性,我们不妨拎出相邻的大臣i与大臣j。

设这两位大臣之前的大臣获得的奖金为y,之前的所有大臣左手上的数之和为x。

①当大臣1排在大臣2之前时:

大臣i的奖金:max( y,x+ai )+bi

大臣j的奖金:max( ci,x+ai+a)+bj

②当大臣1排在大臣2之前时:

大臣j的奖金:max( y,x+aj )+bj

大臣i的奖金:max( cj,x+ai+a)+bi

我们比较两种情况,分析满足何种条件时我们才能把大臣i放在前面。

显然,当一个大臣被放在后面时,一定比他放在前面时得到的奖金多(证明略)

为了比较奖金最多大臣的奖金多少,我们进而比较被放在后面时两个大臣的奖金数。

为使情况最优,max( ci,x+ai+a)+b< max( cj,x+ai+a)+bi

=> max( max( y,x+ai )+bi,x+ai+a)+b< max( max( y,x+aj )+bj,x+ai+a)+bi

=> max( y+bi,x+ai+bi,x+ai+a)+b< max( y+bj,x+aj+bj,x+ai+a)+bi

=> max( y+bi+bj,x+ai+bi+bj,x+ai+a+bj) < max( y+bj+bi,x+aj+bj+bi,x+ai+aj+bi )

 由于两式中都有 y+bi+bj,我们忽略不计算。

=>  max( x+ai+bi+bj,x+ai+a+bj) < max( x+aj+bj+bi,x+ai+aj+bi )

为化简式子,我们同时减去 x+ai+aj+bi+bj

=> max( -aj,-bi) < max( -ai,-bj )

=> min( aj,b) < min( ai,bj )

 

Part 2

于是如果您的sort的cmp函数写成:

bool operator <(node a) const

     return min(x,a.y)<min(y,a.x);

或许能水过洛谷的数据,但是是错解。

这里从Luogu题解中找到了一组hack数据:

2

7

6 3

1 1

7 3

1 1

1 6

1

6 10

 

7

10

1

3

1

3

1

1 6

上面两组数据只是顺序不一样,结果应该是一样的,但用上面的程序跑出来的结果却是不一样的。

再具体地分析一下。假设有三位大臣,他们的a[i]和b[i]分别是:

7 3

1 1

1 6

显然,这样可以是排完序后的结果,因为两两之间用条件判断都是等于。这样算出来答案是17。而如果这样排:

1 1

1 6

7 3

答案是12,显然这样更优,但程序却有可能排成17的那种情况。

为什么错了呢?简单来说,就是此时的判断条件不满足传递性。引用一个名词——严格弱序。sort的判断函数必须满足严格弱序。

严格弱序是什么?

拿内置类型来说,C++都定义了 “<”操作符,这就是一个严格弱序,而“<=”就不是一个严格弱序

对于内置类型我们自然可以有<、>、=来判断两个值的大小关系,而对于自定义的类型,只用一个严格弱序(这里就用<为例)就可以表示两个元素三种大小关系

a小于b

a < b

b小于a

b < a

a等于b

!(a < b) && !( b < a )

严格弱序的三点要求:

1.两个关键字不能同时“严格弱序”于对方

2.如果a“严格弱序”于b,且b“严格弱序”于c,则a必须“严格弱序”于c(传递性)

3.如果存在两个关键字,任何一个都不“严格弱序”于另一个,则这两个关键字是相等的。

摘自WikiPedia的定义:

strict weak ordering is a binary relation < on a set S that is a strict partial order (a transitive relation that is irreflexive, or equivalently,[5] that is asymmetric) in which the relation "neither a < b nor b < a" is transitive.[1] Therefore, a strict weak ordering has the following properties:

  • For all x in S, it is not the case that x < x (irreflexivity).
  • For all xy in S, if x < y then it is not the case that y < x (asymmetry).
  • For all xyz in S, if x < y and y < z then x < z (transitivity).
  • For all xyz in S, if x is incomparable with y (neither x < y nor y < x hold), and y is incomparable with z, then x is incomparable with z (transitivity of incomparability).

This list of properties is somewhat redundant, as asymmetry follows readily from irreflexivity and transitivity.

非严格弱序带来的问题:

有序关联容器不允许存在相同的关键字,在判断时,会认为相同的关键字是不相等的,因此会将两个相同的关键字插入容器中,这个行为是未定义的。

技术图片

注:以上部分严格弱序的叙述摘自 C++ 严格弱序  River_Lethe

 

Part 3

那么,如果必须使用严格弱序,应该如何判断 min( aj,b) < min( ai,bj ) 呢?

我们分情况讨论:

1.当ai biajbj?时,ai≤ aj?,应该按a升序排序(ai?aj?相等时无所谓)。

2.当aibi?ajbj?时,爱怎么排怎么排。

3.当aibi?ajbj?时,bi? ≥ bj?,应该按b降序排序。

//判断a[i].x 与 b[i].x 的大小关系
if (a[i].x>a[i].y) a[i].d=1;
else if (a[i].x<a[i].y) a[i].d=-1;
else a[i].d=0;

于是cmp将是这样的:

bool operator <(node a) const

    if (d!=a.d) return d<a.d;
    if (d<=0) return x<a.x;
    return y>a.y;

 

以上是关于邻项交换排序的主要内容,如果未能解决你的问题,请参考以下文章

poj3045 cow acrobats 贪心/邻项交换

加工生产调度

用C++交换排序

有啥算法是相邻交换排序的(除了冒泡以外)

交换排序:冒泡排序

排序算法5--交换排序--快速排序