算法导论随笔 (一)
高中的时候曾经看过同学拿这本书作参考。当时翻阅的时候第一反应是自己肯定看不下去,第二反应是内容太多了对于OI应该性价比不是很高。
当然,此书意义非凡,不是OI能衡量的,现在刚刚放假,于是计划有目的地通读,当然第一遍阅读,目标主要是掌握要点,深度方面必然还需要之后补漏,这里仅记录在阅读中自己较为有价值的思考。
最大子段和相关
- 在之前的校赛中,我记得有一个猪肉买卖问题:
-
给出一个序列代表每天的猪肉价格,我们可以选择在某天买入然后在之后某天卖出,求最大收益。
-
而经典的最大子段和问题是,在序列中选取一段连续子序列的和,求这个最大和。
-
在读算法导论之前我没有将这两个问题联系到一起,尽管问题简单,但是这一点也要想到:两问题本质是一样的。将最大子段和问题中的序列求一遍前缀和,之后原问题就转化为了在前缀和数组上的猪肉问题。
-
转化后重做水题:luogu1115 最大字段和
-
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int n;
int main ()
{
scanf("%d", &n);
long long minn = 0;//前缀和最小值
long long su = 0; //前缀和变量
long long ans = -9999999999; //答案
for (int i = 1; i <= n; i++)
{
long long xx;
scanf("%lld", &xx);
ans = max(ans, xx);
su += xx;
if (minn > su)
{
minn = su;
}
else
{
ans = max(ans, su - minn);
}
}
printf("%d\n", ans);
return 0;
}
-
继续扩展水题:NOIP2013/2018 积木大赛
- 无论是积木大赛还是铺设道路,两道题都是一个做法,就是猪肉问题的扩展——原先只能买一次卖一次,现在能买卖任意次,求最大收益
- 反向转化猪肉问题为最大字段和问题:将序列当做前缀和数组,并且进行还原数组操作。
- 问题就转化为:在得到的数组上选取任意多的不重叠的子段和相加,求最大和,也就是把所有正数加起来就可以了。
- 无论是积木大赛还是铺设道路,两道题都是一个做法,就是猪肉问题的扩展——原先只能买一次卖一次,现在能买卖任意次,求最大收益
-
转化后重做水题:NOIP2013/2018 积木大赛
-
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
long long x, y, co = 0;
int main()
{
scanf("%d", &n);
scanf("%lld", &x);
co = x;
for (int i = 1; i < n; i++)
{
scanf("%lld", &y);
if (y > x)//x为sum[i - 1],y为sum[i] y - x也就是还原a[i]
{
co += y - x;
}
x = y;
}
printf("%lld", co);
return 0;
}