zoukankan      html  css  js  c++  java
  • 动态规划--最大子段和

     
      最大子段和是一个十分经典的问题。 
    给定由n个整数(包含负整数)组成的序列a1,a2,...,an,求该序列子段和的最大值。
    当所有整数均为负值时定义其最大子段和为0。
    例如,当(a1,a2, ……a7,a8)=(1,-3, 7,8,-4,12, -10,6)时,
    最大子段和为:23
    bj是1到j位置的最大子段和:

    a1

    a2

    ai

    aj

    an-1

    an

                                                                                             |《-------bj--------------》|
     
    由bj的定义易知,当bj-1>0时bj=bj-1+aj,否则bj=aj。
    则计算bj的动态规划递归式:
    bj=max{bj-1+aj,aj},1≤j≤n。
     

     

    1

    2

    3

    4

    5

    6

    a[i]

    -2

    11

    -4

    13

    -5

    -2

    b(初值=0)

    -2

    11

    7

    20

    15

    13

    sum

    0

    11

    11

    20

    20

    20

     
    求最大值:
     1 #include<iostream>
     2 using namespace std;
     3 
     4 int MaxSum(int n)
     5 {
     6     int sum = 0;
     7     int b = 0;
     8     for(int i=1; i<=n; i++)
     9     {
    10         if(b>0) b+=a[i]; else b=a[i];
    11         if(b>sum) sum = b;
    12     }
    13     return sum;
    14 }
    15 
    16 int main()
    17 {
    18     
    19 }
    View Code


    构造最优值:

     1 #include<iostream>
     2 using namespace std;
     3 
     4 const int MAXN = 1001;
     5 int a[MAXN];
     6 
     7 int MaxSum(int n, int &besti, int &bestj)
     8 {
     9     int sum = 0;
    10     int b = 0;
    11     int begin = 0;
    12     for(int i=1; i<=n; i++)
    13     {
    14         if(b>0) b+=a[i];
    15         else 
    16         {
    17             b=a[i]; begin = i;
    18         }
    19         if(b>sum)
    20         {
    21             sum = b;
    22             besti = begin;
    23             bestj = i;
    24         }
    25     }
    26     return sum;
    27 } 
    View Code

     

     
     
     当然上面动态规划的算法是最快的算法, 时间复杂度为 O(n). 
    另外还有最直接的解法: 暴力算法
    实现起来稍微更麻烦的算法: 分治算法
     
     
     暴力解法:时间复杂度O(n^2)   即: P(n, 2) 的运算量 
    #include <iostream>
    using namespace std; 
    
    const int MAXN = 1001; 
    int a[MAXN]; 
    
    int MAXSum(int n, int &besti, int &bestj)
    {
        int Best_sum = 0;
        int sum = 0; 
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= i; j++)
            {
                sum = 0; 
                for (int k = j; k <= i; k++)
                    sum += a[k]; 
                if (Best_sum < sum)
                {
                    Best_sum = sum; 
                    besti = i; 
                    bestj = j; 
                }
            }
        return Best_sum; 
    }
    
    int main()
    {
        int low = 0, high = 0, best_sum = 0; 
        int n; 
        cin >> n; 
        for(int i = 1; i <= n; i++)
            cin >> a[i]; 
        best_sum = MAXSum(n, high, low);
    
        cout << "From " << low << " to " << high << " is
    "; 
        cout << "the best sum: " << best_sum << endl; 
        
        return 0; 
    }
    View Code

     

     

    分治解法: 时间复杂度O( nlg(n) ) 

    #include <iostream>
    using namespace std; 
    
    const int MAXN = 1010;
    int A[MAXN]; 
    
    int findMaxCrossingSubArray(int A[], int low, int mid, int high)
    {
        int left_sum = -0x7fffffff; 
        int sum = 0; 
        for (int i = mid; i >= low; i--)
        {
            sum = sum + A[i]; 
            if (sum > left_sum)
            {
                left_sum = sum; 
            }
        }
        
        int right_sum = -0x7fffffff; 
        sum = 0; 
        for (int j = mid + 1; j <= high; j++)
        {
            sum = sum + A[j]; 
            if (sum > right_sum)
            {
                right_sum = sum;  
            }
        }
        return (left_sum + right_sum); 
    }
    
    int findMaximumSubArray(int A[], int low, int high)
    {
        if (high == low)
        {
            return A[low]; 
        }
        else 
        {
            int mid = (low + high) / 2; 
            int left_sum = findMaximumSubArray(A, low, mid); 
            int right_sum = findMaximumSubArray(A, mid+1, high); 
            int cross_sum = findMaxCrossingSubArray(A, low, mid, high); 
            if (left_sum >= right_sum && left_sum >= cross_sum)
                return left_sum; 
            else if (right_sum >= left_sum && right_sum >= cross_sum)
                return right_sum; 
            else 
                return cross_sum; 
        }
    }
    int main()
    { 
        int n; 
        cin >> n; 
        for(int i = 1; i <= n; i++)
            cin >> A[i]; 
    
        int best_sum = findMaximumSubArray(A, 1, n); 
        cout << "the best sum: " << best_sum << endl; 
        
        return 0; 
    }
    View Code

     

     
     
     
     
     
  • 相关阅读:
    精确率、召回率、F1 值、ROC、AUC 各自的优缺点是什么?
    使用sklearn做单机特征工程
    机器学习算法比较
    CNN-卷积层和池化层学习
    卷积神经网络概念与原理
    CNN(卷积神经网络)、RNN(循环神经网络)、DNN(深度神经网络)概念区分理解
    技能|三次简化一张图:一招理解LSTM/GRU门控机制
    【转】TensorFlow四种Cross Entropy算法实现和应用
    http://blog.csdn.net/u014595019/article/details/52805444
    神经网络和深度学习简史(三)
  • 原文地址:https://www.cnblogs.com/acm1314/p/4578577.html
Copyright © 2011-2022 走看看