第四章 4.1最大子数组问题(分治)

4.1-1 当A的所有元素均为负数时,FIND-MAXIMUM-SUBARRAY返回什么?

最小负数值,及其下标

4.1-2 对最大子数组问题,编写暴力求解方法的伪代码,其运行时间应该为 θ(n2)

可运行代码如下:

#include "stdafx.h"
#include<stdlib.h>
class Solve
{
public:
    Solve();
    int begin;
    int end;
    int sum;

};
Solve::Solve()
    {
        begin=0;
        end=0;
        sum=-65535;
    }
int _tmain(int argc, _TCHAR* argv[])
{
    int A[]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
    //暴力求解算法
    int sum=0;
    Solve solve;
    int size=sizeof(A)/sizeof(A[0]);
    for(int i=0;i<size;i++)
    {
        sum=0;
        for(int j=i;j<size;j++)
        {
            sum+=A[j];
            if(sum>solve.sum)
            {
                solve.begin=i;
                solve.end=j;
                solve.sum=sum;
            }
        }
    }
    printf("彩票买入为:第%d天;彩票卖出为:第%d天;净赚:%d元;\n",solve.begin+1,solve.end+1,solve.sum);
    system("pause");
    return 0;
}
4.1-3 在你的计算机上实现最大子数组问题的暴力算法和递归算法。请指出多大的问题规模 n0 是性能交叉点——从此之后递归算法将击败暴力算法?然后,修改递归算法的基本情况——当问题规模小于 n0 时采用暴力算法。修改后,性能交叉点会改变么?

递归算法实现如下:

// test4.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<stdlib.h>
class Solve
{
public:
    Solve();
    int begin;
    int end;
    int sum;

};
Solve::Solve()
    {
        begin=0;
        end=0;
        sum=-65535;
    }
Solve findCrossing(int *A,int low,int mid,int high)
{
    //确定左侧的起始点
    Solve solveleft;
    solveleft.sum=-65535;
    int sum=0;
    for(int i=mid;i>=low;i--)
    {
        sum+=A[i];
        if(sum>solveleft.sum)
        {
            solveleft.sum=sum;
            solveleft.begin=i;
            solveleft.end=mid;//条理上清晰,不加这条语句也可以
        }
    }
    //确定右侧的终点
    Solve solveright;
    solveright.sum=-65535;
    sum=0;
    for(int i=mid+1;i<=high;i++)
    {
        sum+=A[i];
        if(sum>solveright.sum)
        {
            solveright.sum=sum;
            solveright.end=i;
            solveright.begin=mid;//条理上清晰,不加这条语句也可以
        }
    }
    Solve solve;
    solve.begin=solveleft.begin;
    solve.end=solveright.end;
    solve.sum=solveleft.sum+solveright.sum;
    return solve;
}

Solve findMax(int *A,int low,int high)
{
    Solve solve;
    if(high==low)
    {
        solve.begin=low;
        solve.end=high;
        solve.sum=A[low];
        return solve;
    }
    else
    {
        int mid=(low+high)/2;
        Solve solveleft=findMax(A,low,mid);
        Solve solveright=findMax(A,mid+1,high);
        Solve solvecross=findCrossing(A,low,mid,high);
        if(solveleft.sum>=solveright.sum&&solveleft.sum>=solvecross.sum)
        {
            return solveleft;
        }
        else if(solveright.sum>=solveleft.sum&&solveleft.sum>=solvecross.sum)
        {
            return solveright;
        }
        else
        {
            return solvecross;
        }
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
    int A[]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
    int size=sizeof(A)/sizeof(A[0]);
    Solve solve=findMax(A,0,size-1);
    printf("彩票买入为:第%d天;彩票卖出为:第%d天;净赚:%d元;\n",solve.begin+1,solve.end+1,solve.sum);
    system("pause");
    return 0;
}
4.1-4 假定修改最大子数组的定义,允许结果为空子数组,其和为0。你应该如何修改现有的算法,使他们能允许空子数组为最终结果?

在最后输出结果前,加一条判断,如果solve.sum<0,则结果为空数组,其和为0。
或者sum的最小值不是-65535,而是0。

4.1-5 使用如下思想为最大子数组问题设计一个非递归的、线性时间的算法。从数组的左边界开始,由左至右处理,记录到目前为止已经处理过得最大子数组。若已知A[1…j]的最大子数组,基于如下性质将解扩展为A[1…j+1]的最大子数组:A[1…j+1]的最大子数组要么是A[1…j]的最大子数组,要么是某个子数组A[i…j+1] ( 1ij+1 )。在已知A[1…j]的最大子数组的情况下,可以在线性时间内找到形如A[i…j+1]的最大子数组。
int _tmain(int argc, _TCHAR* argv[])
{
    int A[]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
    int size=sizeof(A)/sizeof(A[0]);
    //线性时间算法。
    int sum=0;
    Solve solve;
    for(int i=0;i<size;i++)
    {
        sum=0;
        for(int j=i+1;j>=0;j--)
        {
            sum+=A[j];
            if(sum>solve.sum)
            {
                solve.begin=j;
                solve.end=i+1;
                solve.sum=sum;
            }
        }
    }
    printf("彩票买入为:第%d天;彩票卖出为:第%d天;净赚:%d元;\n",solve.begin+1,solve.end+1,solve.sum);
    system("pause");
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值