推公式算法的实现

简介: 推公式算法的实现

农民约翰的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

输入样例:

3

10 3

2 5

3 3

输出样例:

2

(贪心)

思路: 与国王游戏的贪心策略相似, 我们先分析每头牛的危险值 = 他前面牛的w(重量值)和 - 自身的s(强壮值),要使每头牛的危险值最小,这显然是与w 和 s同时相关,所以先 yy 出一种做法按 每头牛的w + s进行升序排序(题见多了可能就会有这种题感)。接下来进行数学分析证明:

牛 交换前 交换后

ii

∑j=1i−1wj−si

∑j=1i−1wj−si

∑j=1i−1wj+wi+1−si

∑j=1i−1wj+wi+1−si

i+1i+1

∑j=1iwj−si+1

∑j=1iwj−si+1

∑j=1i−1wj−si+1

∑j=1i−1wj−si+1

其他牛的危险值显然不变,所以分析交换前后这两头牛中最大的危险值即可。

将上述式子进行化简,每个式子减去 ∑i−1j=1wj∑j=1i−1wj得到如下式子

牛 交换前 交换后

ii

−si

−si

wi+1−si

wi+1−si

i+1i+1

wi−si+1

wi−si+1

−si+1

−si+1

由于s, w都是正数,wi−si+1>−si+1wi−si+1>−si+1 , wi+1−si>−siwi+1−si>−si

比较wi−si+1wi−si+1, wi+1−siwi+1−si即可

当wi−si+1>=wi+1−siwi−si+1>=wi+1−si,即 wi+si>=wi+1+si+1wi+si>=wi+1+si+1时, 交换后更优

当wi−si+1<wi+1−siwi−si+1<wi+1−si,即 wi+si<wi+1+si+1wi+si<wi+1+si+1时, 交换前更优

所以得到做法: 按每头牛的 w + s 进行排序, 当存在逆序时就进行交换(即升序排序),

然后根据题意算出每头牛的危险值记录其中的最大值即可

代码:

#include
#include
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 5e4 + 5;
PII a[N];
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i ++ )
{
int x, y;
scanf(“%d %d”, &x, &y);
a[i].first = x + y;
a[i].second = y;
}
sort(a, a + n);
ll res = -1e18, sum = 0;
for(int i = 0; i < n; i ++ )
{
sum -= a[i].second;
res = max(res, sum);
sum += a[i].first;
}
cout << res << endl;
return 0;
}

底下的牛的强壮程度SS越大越好

上面牛的重量和WW越小越好(越重的放越下面)

=>

直觉是S[i]+W[i]越大的放越下面

证:

贪心得到的答案≥最优解(根据最优解定义:所有排序方案的最小值)

贪心得到的答案≤最优解

如果不是按S[i]+W[i]从小到大排序一定存在相邻i和i+1有wi+si>wi+1+si+1wi+si>wi+1+si+1

可以发现此时交换第ii头牛和第i+1i+1头牛不影响[0,i−1][0,i−1]和[i+2,n][i+2,n]的风险

变化 第ii个位置上的牛 第i+1i+1个位置上的牛

交换前

w1+…+w(i−1)−si

w1+…+w(i−1)−si

w1+…+w(i)−s(i+1)

w1+…+w(i)−s(i+1)

交换后

w1+…+w(i−1)−s(i+1)

w1+…+w(i−1)−s(i+1)

w1+…+w(i−1)+w(i+1)−s(i)

w1+…+w(i−1)+w(i+1)−s(i)

前i−1i−1项减去

变化 第ii个位置上的牛 第i+1i+1个位置上的牛

交换前

−si

−si

w(i)−s(i+1)

w(i)−s(i+1)

交换后

−s(i+1)

−s(i+1)

w(i+1)−s(i)

w(i+1)−s(i)

加上si+si+1si+si+1

变化 第ii个位置上的牛 第i+1i+1个位置上的牛

交换前

s(i+1)

s(i+1)

wi+si

wi+si

交换后

si

si

w(i+1)+s(i+1)

w(i+1)+s(i+1)

wi+si>siwi+si≥w(i+1)+s(i+1)wi+si≥max(si,w(i+1)+s(i+1))由wi+si>wi+1+si+1−>wi+si>si+1−>wi+si=max(s(i+1),wi+si)max(s(i+1),wi+si)≥max(si,w(i+1)+s(i+1))max(交换前)≥max(交换后)所有风险的最大值起码不会变大即只要wi+si不是严格递增,则我们可以把他们变成递增的并且所有风险的最大值不会变大

wi+si>siwi+si≥w(i+1)+s(i+1)wi+si≥max(si,w(i+1)+s(i+1))由wi+si>wi+1+si+1−>wi+si>si+1−>wi+si=max(s(i+1),wi+si)max(s(i+1),wi+si)≥max(si,w(i+1)+s(i+1))max(交换前)≥max(交换后)所有风险的最大值起码不会变大即只要wi+si不是严格递增,则我们可以把他们变成递增的并且所有风险的最大值不会变大

#include
#include
using namespace std;
typedef pair<int,int> PII;
const int N=50010;
#define x first
#define y second
int n;
PII cow[N];
int main()
{
cin >> n;
for(int i=0;i<n;i++)
{
int w,s;
cin >> w >> s;
cow[i] = {w+s,w};
}
sort(cow,cow+n);
int res = -1e9,sum=0;
for(int i=0;i<n;i++)
{
int s;
s = cow[i].x-cow[i].y;
res = max(res,sum-s);//风险 = 上面的重量-当前的承受
sum+=cow[i].y;
}
cout << res;
return 0;
}


相关文章
|
4月前
|
算法
算法题(5)
算法题(5)
31 11
|
5月前
|
算法
Manacher(马拉车)算法详解
该文章详细解释了Manacher算法,这是一种高效找出给定字符串最长回文子串的算法,通过在字符串中插入特殊字符构建新的字符串,并利用中心扩展策略来找出最长回文序列,时间复杂度为O(N),空间复杂度为O(N)。
|
5月前
|
人工智能 算法 搜索推荐
什么是算法?一切皆算法
如果有人问我什么算法?我就一句话:算法就是对一类问题的最优求解路径。
|
6月前
|
算法 调度 C#
|
7月前
|
算法
一道算法题
一道算法题
27 0
|
自然语言处理 算法 程序员
解答算法题的一个小技巧
解答算法题的一个小技巧
|
传感器 人工智能 算法
图象处理算法(介绍)
图象处理算法(介绍)
|
算法
【算法之初步认识】
【算法之初步认识】
156 0
【算法之初步认识】
|
算法
左神起百算,成机算法魂
左神起百算,成机算法魂
115 0
算法硬算能提升多少
解决一个问题,想到一个方法,设计个对应的模型,开始训练吧。。。。 是这个思路没错吧(别较真,较真你就输了。) 然后就是慢长的等待,2天,3天。。。 transformer的WMT训练了3.5天,几天的训练是家常便饭了现在。
820 0

热门文章

最新文章