编程语言
首页 > 编程语言> > 贪心算法:推公式 耍杂技的牛

贪心算法:推公式 耍杂技的牛

作者:互联网

C++

AcWing 125. 耍杂技的牛

/*
题目描述:
	Acwing 125. 耍杂技的牛:
	农民约翰的 N 头奶牛(编号为 1..N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。
	奶牛们不是非常有创意,只提出了一个杂技表演:
	叠罗汉,表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。
	奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。
	这 N 头奶牛中的每一头都有着自己的重量 Wi 以及自己的强壮程度 Si。
	一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。
	您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能的小。

	输入格式:
	第一行输入整数 N,表示奶牛数量。
	接下来 N 行,每行输入两个整数,表示牛的重量和强壮程度,第 i 行表示第 i 头牛的重量 Wi 以及它的强壮程度 Si。

	输出格式:
	输出一个整数,表示最大风险值的最小可能值。

	数据范围:
	1 ≤ N ≤ 50000,
	1 ≤ Wi ≤ 10,000,
	1 ≤ Si ≤ 1,000,000,000

解题思路:
	对于本题,乍一看基本没什么明显的思路,因此,我们从交换 i 和 i + 1 牛的位置入手,查看什么时候交换 i 和 i + 1 牛的位置,可以使得其对结果更好。

	为什么选择 i 和 i + 1 ? 
		因为 交换 i 和 i + 1头牛的位置,对其他位置的牛危险值的计算没有影响,他**只会影响** i 和 i + 1 头牛风险值的大小。
		那么,我们只需要通过查看交换时候风险值是否变大,来决定是否需要交换。

	公式推导部分:
		首先我们假设当前顺序奶牛们的重量为 w1, ..., wn, 强壮程度 s1, ..., sn,方便比较假设 x = sum(w1, ..., w(i-1))
		可得 **交换前风险值**
			第 i 头奶牛: 		x - si
			第 i + 1 头奶牛: 	x + wi - s(i+1)
		可得 **交换后风险值**
			第 i 头奶牛: 		x - s(i+1)
			第 i + 1 头奶牛: 	x + w(i+1) - s(i)
		需要交换的情况:
			max(x - si, x + wi - s(i+1)) > max(x - s(i+1), x + w(i+1) - s(i))
		不需要交换的情况
			max(x - si, x + wi - s(i+1)) < max(x - s(i+1), x + w(i+1) - s(i))
		也就是我们需要选择 i 和 i + 1 头奶牛 max 风险值最小的那一个。我们以不需要交换情况为基础进行推导
		该问题可以选择的推导思路,首先判断 x - si 和 x + wi - s(i+1)的大小
		1. (x - si) < (x + wi - s(i+1)) 即为 s(i+1) - s(i) < w(i)
			max(x - si, x + wi - s(i+1)) = x + wi - s(i+1) < max(x - s(i+1), x + w(i+1) - s(i))
			因为 x + wi - s(i+1) >= x - s(i+1) 显然成立,
			因此不等式成立条件为
				x + wi - s(i+1) < x + w(i+1) - s(i)
			即为:
				wi + si < w(i+1) + s(i+1)
		2. (x - si) > (x + wi - s(i+1)) 即为 s(i+1) - s(i) > w(i)
			max(x - si, x + wi - s(i+1)) = x - si < max(x - s(i+1), x + w(i+1) - s(i))
			因为 x - si <= x + w(i+1) - s(i)) 显然成立,
			因此等式恒成立。
		
		讨论一可以得之,不等式成立条件为 s(i+1) - s(i) < w(i) && wi + si < w(i+1) + s(i+1) 
		讨论二可以得之,不等式成立条件为 s(i+1) - s(i) > w(i) && True,然而 s(i+1) - s(i) > w(i) 包含了 wi + si < w(i+1) + s(i+1) 

		因此,不等式成立条件为 wi + si < w(i+1) + s(i+1)。
		
		即为 wi + si < w(i+1) + s(i+1) 不需要交换 i, i + 1
			wi + si > w(i+1) + s(i+1) 需要交换 i, i + 1
			wi + si < w(i+1) + s(i+1) 可以交换 i, i + 1,也可以不交换。

		目前为止,我们只是推导出了 i 和 i + 1 的交换特性,该特性是否具有传递性呢? 
			**答案是具有的,因为 wi + si < w(i+1) + s(i+1) 本身只是和自身属性相关,具有传递性。**

			
	综上证明完毕,排序条件为 wi + si < w(i+1) + s(i+1)
 */
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

typedef pair<int, int> PII;
typedef long long LL;

const int N = 50010;
PII a[N];
int n;

bool cmp(const PII &t1, const PII &t2) {
	return t1.first + t1.second <= t2.first + t2.second;
}

LL solution() {
	LL res = -1e15;
	LL pre_weight_sum = 0;

	sort(a + 1, a + n + 1, cmp);

	for (int i = 1; i <= n; i ++ ) {
		res = max(res, pre_weight_sum - a[i].second);
		pre_weight_sum += a[i].first;
	}

	return res;
}


int main()
{
	// input
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++ ) {
		scanf("%d%d", &a[i].first, &a[i].second);
	}

	LL res = solution();


	printf("%d\n", res);

	return 0;
}



标签:include,杂技,max,交换,si,wi,算法,奶牛,贪心
来源: https://www.cnblogs.com/lucky-light/p/16499617.html