AcWing 125. 耍杂技的牛
农民约翰的
N
N
N 头奶牛(编号为
1..
N
1..N
1..N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。
奶牛们不是非常有创意,只提出了一个杂技表演:
叠罗汉,表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。
奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。
这
N
N
N头奶牛中的每一头都有着自己的重量
W
i
Wi
Wi以及自己的强壮程度
S
i
Si
Si。
一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。
您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能的小。
输入格式:
第一行输入整数
N
N
N,表示奶牛数量。
接下来
N
N
N行,每行输入两个整数,表示牛的重量和强壮程度,第
i
i
i行表示第
i
i
i头牛的重量
W
i
Wi
Wi 以及它的强壮程度
S
i
Si
Si。
输出格式:
输出一个整数,表示最大风险值的最小可能值。
贪心策略进行猜想:
根据题意,我们可以得出危险值的公式如下:
每头牛的危险值
D
=
他前面牛的
W
(
重量值
)
之和
−
自身的
S
(
强壮值
)
每头牛的危险值D = 他前面牛的W(重量值)之和 - 自身的S(强壮值)
每头牛的危险值D=他前面牛的W(重量值)之和−自身的S(强壮值)
D
=
W
−
S
D=W-S
D=W−S
由此,我们根据贪心思想,首先应该就会想到,如果要所有奶牛的风险值中的最大值尽可能的小。那么就应该把
W
W
W重量越重的越往底部堆叠
;并且
S
S
S越强壮的越堆叠在下方
。因此,猜想
W
+
S
W+S
W+S的值越大的应该越堆叠在下方。
分析证明:
如图所示,随机一种堆叠方式,那么何时我们才需要任意i和i+1的交换位置呢?
,那自然是任意位置
i
i
i和
i
+
1
i+1
i+1交换之后,可以降低这两个位置中风险值D的最大值
的情况下,才会进行交换。
由图中可知交换 i 和 i + 1 i和i+1 i和i+1的位置并不会影响其他任何位置的危险值。此时已经求出交换 i 和 i + 1 i和i+1 i和i+1的位置前后的危险值 D D D已经求出,为了方便比较,此处将交换前后 D D D中公共值都减去相同 ∑ j = 1 i − 1 W j \sum_{j=1}^{i-1} W_j ∑j=1i−1Wj。
此时,只需要比较交换前后的值简化值即可。
交换前:
i
对应:
−
S
i
(
1
)
i对应: \quad -S_i \quad (1)
i对应:−Si(1)
i
+
1
对应:
W
i
−
S
i
+
1
(
2
)
i+1对应:\quad W_i-S_{i+1}\quad (2)
i+1对应:Wi−Si+1(2)
交换后:
i
对应:
W
i
+
1
−
S
i
(
3
)
i对应: \quad W_{i+1}-S_i\quad (3)
i对应:Wi+1−Si(3)
i
+
1
对应:
−
S
i
+
1
(
4
)
i+1对应:\quad-S_{i+1} \quad (4)
i+1对应:−Si+1(4)
达到降低这两个位置中风险值D的最大值
的效果,才会进行交换。即满足以下公式才进行交换
m
a
x
[
(
1
)
,
(
2
)
]
<
m
a
x
[
(
3
)
,
(
4
)
]
max[(1),(2)]<max[(3),(4)]
max[(1),(2)]<max[(3),(4)]
由于任意
W
W
W和
S
S
S都为正数很明显可以看出,
W
i
+
1
−
S
i
>
−
S
i
和
W
i
−
S
i
+
1
>
−
S
i
+
1
W_{i+1}-S_{i}> -S_i \quad和\quad W_i-S_{i+1}>-S_{i+1}
Wi+1−Si>−Si和Wi−Si+1>−Si+1。
故只需比较 W i − S i + 1 W_i-S_{i+1} Wi−Si+1和 W i + 1 − S i W_{i+1}-S_i Wi+1−Si的大小即可。因为无外乎两种情况,一种是最大值有变大,另一种是最大值变小。
如果
W
i
−
S
i
+
1
>
W
i
+
1
−
S
i
W_i-S_{i+1}>W_{i+1}-S_i
Wi−Si+1>Wi+1−Si,交换前后危险值的最大值
m
a
x
(
D
i
,
D
i
+
1
)
max(D_i,D_{i+1})
max(Di,Di+1)必然是变小了。因为
W
i
−
S
i
+
1
>
W
i
+
1
−
S
i
W_i-S_{i+1}>W_{i+1}-S_i
Wi−Si+1>Wi+1−Si成立且
W
i
−
S
i
+
1
>
−
S
i
+
1
W_i-S_{i+1}>-S_{i+1}
Wi−Si+1>−Si+1,所以
W
i
−
S
i
+
1
W_i-S_{i+1}
Wi−Si+1大于交换后的所有值
,即
W
i
−
S
i
+
1
W_i-S_{i+1}
Wi−Si+1大于交换后的最大值
。此时,无论交换前
W
i
−
S
i
+
1
W_i-S_{i+1}
Wi−Si+1是最大值还是
−
S
i
-S_i
−Si是最大值,都可以得出交换前的最大值大于交换后的最大值
,即进行交换后,危险值的最大值
m
a
x
(
D
i
,
D
i
+
1
)
max(D_i,D_{i+1})
max(Di,Di+1)降低了。
如果
W
i
−
S
i
+
1
<
W
i
+
1
−
S
i
W_i-S_{i+1}<W_{i+1}-S_i
Wi−Si+1<Wi+1−Si,交换前后危险值的最大值
m
a
x
(
D
i
,
D
i
+
1
)
max(D_i,D_{i+1})
max(Di,Di+1)必然是变大了。因为
W
i
−
S
i
+
1
<
W
i
+
1
−
S
i
W_i-S_{i+1}<W_{i+1}-S_i
Wi−Si+1<Wi+1−Si成立且
−
S
i
<
W
i
+
1
−
S
i
-S_i<W_{i+1}-S_{i}
−Si<Wi+1−Si,所以
W
i
+
1
−
S
i
W_{i+1}-S_{i}
Wi+1−Si大于交换前的所有值
,即
W
i
+
1
−
S
i
W_{i+1}-S_{i}
Wi+1−Si大于交换前的最大值
。此时,无论交换后
W
i
+
1
−
S
i
W_{i+1}-S_{i}
Wi+1−Si是最大值还是
−
S
i
+
1
-S_{i+1}
−Si+1是最大值,都可以得出交换后的最大值大于交换前的最大值
,即进行交换后,危险值的最大值
m
a
x
(
D
i
,
D
i
+
1
)
max(D_i,D_{i+1})
max(Di,Di+1)提高了。
此时交换前后,危险值的最大值的比较问题已经解决。
回归到正题。那么何时我们才需要任意i和i+1的交换位置呢?
,当两个位置中风险值D的最大值降低
就进行交换。即需要满足
W
i
−
S
i
+
1
>
W
i
+
1
−
S
i
W_i-S_{i+1}>W_{i+1}-S_i
Wi−Si+1>Wi+1−Si才进行交换。最终可得公式
W
i
+
S
i
>
W
i
+
1
+
S
i
+
1
W_i+S_i>W_{i+1}+S_{i+1}
Wi+Si>Wi+1+Si+1
只有满足上述公式时,才能保证任意i和i+1位置的奶牛交换后,危险值的最大值降低。以图中堆叠的视角来看,就是只有堆叠在上方的重量
W
W
W和强壮值
S
S
S大于堆叠在下方重量
W
W
W和强壮值
S
S
S时,才需要向下交换位置,从而一步一步实现危险值的最大值的最小情况,否则的话说明堆叠的情况已经是危险值最大值的最小情况了。
AC代码
经过上述分析后,得出规律W+S越大,越应该堆叠在下面是正确。由此得到以下AC代码:
#include<iostream>
#include<algorithm>
#include <climits>
using namespace std;
const int N = 50010;
struct COW
{
int w, s;
bool operator<(const COW& c)const {
return w + s < c.w + c.s;
}
}cow[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> cow[i].w >> cow[i].s;
//升序排序
sort(cow, cow + n);
//结果可能是负值,初始化为int最小值
int res = INT_MIN;
//记录某个奶牛的上方的累积重量
int weights = 0;
for (int i = 0; i < n; i++) {
res = max(res, weights - cow[i].s);
weights += cow[i].w;
}
cout << res << endl;
return 0;
}