zoukankan      html  css  js  c++  java
  • 分治策略

    在分治策略中递归地求解一个问题,在每层递归中应用如下三个步骤:

    分解 : 将问题划分成一些子问题,子问题的形式与原问题一样,只是规模更小

    解决 : 递归地求解子问题。如果子问题的规模足够小,则停止递归直接求解

    合并 : 将子问题的解组合成原问题的解。

    最大子数组问题

    分治策略求解(nlg(n) )

    low         mid         high

    !                !              !

    #  #  #  #  #  #  #  #  #

    A[low,high]的任何连续子数组的位置必然是下面的三种情况之一:

    * 完全位于子数组 A[low,mid] 中,因此low<=i<=j<=mid;

    * 完全位于子数组 A[mid+1,high]中, 因此mid<i<=j<=high;

    * 跨越了中点,因此low<=i<=mid<j<=high;

    所以A[low,high]的一个最大子数组所处的位置必然是三者之一,是 完全位于子数组 A[low,mid] 中,完全位于子数组 A[mid+1,high]中, 跨越了中点的所有子数组中和最大的;

    我们可以递归地求解A[low.....mid]和A[mid+1....high]的最大子数组,因为这两个子问题仍是最大子数组问题,只是规模更小,因此剩下的工作就是寻找跨越中点的最大子数组,然后4

    在三种情况中选取和最大的;

    分治策略代码:

     1 #include<iostream>
     2 using namespace std;
     3 const int inf=999999;
     4 struct answer{
     5     int sum,left,right;
     6 };
     7 answer find_max_crossing_subarray(int *a,int l,int mid,int r){
     8     int leftsum=-inf;
     9     int sum=0;
    10     int maxleft;
    11     for(int i=mid;i>=l;i--){
    12         sum+=a[i];
    13         if(sum>leftsum){
    14             leftsum=sum;
    15             maxleft=i;
    16         }
    17     }
    18     int rightsum=-inf;
    19     sum=0;
    20     int maxright;
    21     for(int i=mid+1;i<=r;i++){
    22         sum+=a[i];
    23         if(sum>rightsum){
    24             rightsum=sum;
    25             maxright=i;
    26         }
    27     }
    28     answer ans{leftsum+rightsum,maxleft,maxright};
    29     return ans;    
    30 }
    31 answer find_max_subarray(int *a,int l,int r){
    32     if(l==r){
    33        answer ans{a[l],l,r};
    34        return ans;
    35     }else{
    36         int mid=(l+r)/2;
    37         answer ans1=find_max_subarray(a,l,mid);
    38         answer ans2=find_max_subarray(a,mid+1,r);
    39         answer ans3=find_max_crossing_subarray(a,l,mid,r);
    40         if(ans1.sum>=ans2.sum&&ans1.sum>=ans2.sum){
    41             return ans1;
    42         }else if(ans2.sum>=ans1.sum&&ans2.sum>=ans3.sum){
    43             return ans2;
    44         }else{
    45             return ans3;
    46         }
    47     }
    48 }
    49 int main(){
    50     int n;
    51     cin>>n; 
    52     int a[n];
    53     for(int i=0;i<n;i++)
    54         cin>>a[i];
    55     answer ans=find_max_subarray(a,0,n-1);
    56     cout<<ans.left<<" "<<ans.right<<" "<<ans.sum<<endl;
    57     return 0;
    58 } 

     当然也有线性时间的解法(O(n) )

    从头遍历一遍,当sum>max时,更新指针和max; 当sum<0时,将sum归0,因为负数加上去只会让后面的数变小,故舍弃这一段,所以sum=0,更新指针t.

     1 #include<iostream>
     2 using namespace std;
     3 int main(){
     4     int n;
     5     cin>>n;
     6     int a[n];
     7     for(int i=0;i<n;i++)
     8         cin>>a[i];
     9     int sum=0,max=-999999,l=0,r=0,t=0;
    10     for(int i=0;i<n;i++){
    11         sum+=a[i];
    12         if(sum>max){
    13             max=sum;
    14             l=t; r=i;
    15         }else if(sum<0){
    16             sum=0;
    17             t=i+1;
    18         }
    19     }
    20     cout<<l<<" "<<r<<" "<<max<<endl; 
    21     return 0;
    22 }
  • 相关阅读:
    Netty检查连接断开的几种方法
    docker部署RabbitMQ集群
    docker部署elk日志采集系统(kafka方式)
    docker部署elk日志采集系统(tcp方式)
    Chrome浏览器RCE 0Day漏洞PoC公开--漏洞复现
    LLMNR和NetBIOS欺骗--获取win7 ntlm-hash
    利用php配置文件构成后门
    zabbix 用sendEmail发邮件
    Exchange 2013 ecp中启用重置用户密码功能
    CentOS7下使用yum安装MariaDB
  • 原文地址:https://www.cnblogs.com/A-Little-Nut/p/8311676.html
Copyright © 2011-2022 走看看