算法导论随笔 (一)

算法导论随笔 (一)

高中的时候曾经看过同学拿这本书作参考。当时翻阅的时候第一反应是自己肯定看不下去,第二反应是内容太多了对于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;
}

posted @ 2021-01-14 00:28  _int_me  阅读(74)  评论(0编辑  收藏  举报