一、什么是分治法
1、分治法简介
2、分治法的设计思想
3、分治法能解决的问题的特征
二、例题详解
最大子列和问题
一、什么是分治法
1、分治法简介
分治法可以通俗的解释为:把一片领土分解,分解为若干块小部 分,然后一块块地占领征服,被分解的可以是不同的政治派别或是其他什么,然后让他们彼此异化。
分治法的精髓:
分–将问题分解为规模更小的子问题;
治–将这些规模更小的子问题逐个击破;
合–将已解决的子问题合并,最终得出“母”问题的解;
2、分治法的思想
分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
对于一个规模为n的问题,若该问题可以容易地解,比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。
3、分治法能解决的问题的特征
分治法所能解决的问题一般具有以下几个特征:
(1) 该问题的规模缩小到一定的程度就可以容易地解决
(2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
(3) 利用该问题分解出的子问题的解可以合并为该问题的解;
(4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
二、例题
题目:
给定K个整数组成的序列{ N1, N2.,… Nk},“连续子列” 被定义为{ Ni, Ni+1…Nj},其中1≤i≤j≤K。”最大子列和” 则被定义为所有连续子列元素的和中最大者。例如给定序列{-2, 11,-4, 13, -5,-2} ,其连续子列{ 11,-4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下
●数据1 :与样例等价,测试基本正确性;●数据2: 102个随机整数;
●数据3: 103个随机整数;
●数据4: 104个随机整数;
●数据5 : 105个随机整数;
输入格式
输入第一行给出整数K(K<=100000);第二行给出K个整数,其间以空格分隔。
输出格式
在一行中输出最大子列和,如果序列中所有整数都为负数,则输出0。
输入样例
6
-2 11 -4 13 -5 -2
输出样例
20
题目分析
将K个元素分为两部分,mid为中点,左边部分为(left,mid),右边部分为(mid+1,right)。递归求出这两部分的最大子列和。当算法涉及递归的时候,特别需要注意的是递归出口,在这里,递归的出口就是当只有一个元素的时候,若该值大于0,返回该值,小于等于0则返回0。而最大子列和可能出现的情况有三种,第一种在left到mid这个范围中,第二中在mid+1到right这个范围中,第三种就是跨界情况,假设范围为(i,j),其中i<=mid<=j,所以最大子列和取三者的最大值。
代码
#include<iostream>
#include<algorithm>
using namespace std;
int a[100001];
int maxsub(int left,int right){
//递归出口 ,当只有一个元素的时候,大于0的将其返回,否则返回0
if(left==right)
{
if(a[left]>0)
return a[left];
else
return 0;
}
int mid=(left+right)/2;//找到中点
//分的过程
int maxLeft = maxsub(left,mid);
int maxRight = maxsub(mid+1,right);
//求跨界,该子列包括 a[mid],所以由mid为中心向两边求跨界的最大子列和
int borderLeft=0;
int borderRight=0;
int sumLeft =0;
int sumRight=0;
//由中点mid向左扫描
for(int i=mid;i>=left;i--){
borderLeft+=a[i];
if(borderLeft>sumLeft)//向左更新左边最大子列和
sumLeft=borderLeft;
}
//由中点mid向右扫描
for(int i=mid+1;i<=right;i++){
borderRight+=a[i];
if(borderRight>sumRight)//向右更新右边的最大子列和
sumRight=borderRight;
}
// sumRight+sumLeft为该范围跨界的最大子列和
//maxLeft为left到mid范围内的最大子列和
//maxRight为mid+1到right的最大子列和
//返回三者的最大值
return max(max(maxLeft,maxRight),sumRight+sumLeft);
}
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
int sum = maxsub(0,n-1);
cout<<sum<<endl;
}