【算法导论】4.0~4.1

分治策略

4.0

分治策略用递归的方式求解问题,每层递归包括下面三个基本步骤:

  • 分解: 将问题分解成若干个子问题,子问题形式与原问题相同,但规模较小。
  • 解决: 递归地求解子问题,若子问题规模足够小,则停止递归,直接求解。
  • 合并; 将子问题的解合并成原问题的解。

递归式的三种求解方法:

  • 代入法: 猜测+数学归纳法证明。
  • 递归树法: 将递归式转换为一棵树,节点表示递归调用产生的代价。然后用边界和技术求解。
  • 主方法; 可求解形如下面公式的递归式的界:
    T ( n ) = a T ( n / b ) + f ( n ) T(n)=aT(n/b)+f(n) T(n)=aT(n/b)+f(n)

4.1

题目: 给出一支股票n天内的价格,可以在某一天买入一股,并在之后的某天卖出,求可以获得的最大收益是多少。


暴力穷举的时间复杂度为: Θ ( n 2 ) Θ(n^2) Θ(n2)
问题变换:
由输入的价格序列 P [ 0.. n ] P[0..n] P[0..n]可生成一个新序列 A [ 1... n ] A[1...n] A[1...n],其中 A i A_i Ai表示第 i i i天和第 i − 1 i-1 i1天的差价。则问题转换为:求出 A A A的一个连续子序列,是其和最大(股票价格净变化值最大)。这样的子数组被称为:最大子数组


分支策略求解:

  1. 分解: 将数组 A [ p . . . q ] A[p...q] A[p...q]从中间分解成两个子数组 L [ p . . . m i d ] L[p...mid] L[p...mid] R [ m i d + 1... q ] R[mid+1. ..q] R[mid+1...q]
  2. 解决: 当子数组长度为1时,该子数组的最大子数组即为其自身。
  3. 合并: 对于数组 A [ p . . . q ] A[p...q] A[p...q]其最大子数组有三种情况:
    • 全部位于 L [ p . . . m i d ] L[p...mid] L[p...mid]中全部位于 L [ p . . . m i d ] L[p...mid] L[p...mid]中。
    • 全部位于 R [ m i d + 1... q ] R[mid+1...q] R[mid+1...q]中全部位于 R [ m i d + 1... q ] R[mid+1...q] R[mid+1...q]中。
    • 跨越 m i d mid mid一半在 L L L中,一半在 R R R中跨越 m i d mid mid一半在 L L L中,一半在 R R R中。

代码如下:

/*最大子序列*/
#define _CRT_SECURE_NO_WARNINGS
#define MAXN 9999999999
#include<stdio.h>
long long int cal(long long int a[], long long int p, long long int q)
{
	long long int m = (p + q) / 2, max_l, max_r, max_m, max_m_l, max_m_r, i, sum, ans;
	if (p == q) return a[p];
	max_l = cal(a, p, m);
	max_r = cal(a, m + 1, q);
	max_m_l = -MAXN;
	sum = 0;
	for (i = m; i > 0; i--)
	{
		sum += a[i];
		if (sum > max_m_l)
			max_m_l = sum;
	}
	max_m_r = -MAXN;
	sum = 0;
	for (i = m + 1; i <= q; i++)
	{
		sum += a[i];
		if (sum > max_m_r)
			max_m_r = sum;
	}
	max_m = max_m_l + max_m_r;
	ans = max_l > max_r ? max_l : max_r;
	if (max_m > ans)
		ans = max_m;
	return ans;
}
void main()
{
	long long int n, i, ans, a[100000];
	scanf("%lld", &n);
	for (i = 1; i <= n; i++)
		scanf("%lld", &a[i]);
	/*解决股票问题(读入循环改为 i = 0 to n-1;下面 cal() 函数 n 改为 n-1;)
	for (i = n - 1; i > 0; i--)
		a[i] = a[i] - a[i - 1];
	*/
	printf("%lld\n", cal(a, 1, n));
	getchar();
	getchar();
	return;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值