第二章作业

                                                             分治法

分治法,老师上课最常说的一个词就是分而治之;

分治法的基本思想:

分治法在书上的定义是将要求解的较大规模的问题分割成k个更小规模的子问题,

对这k个子问题分别求解。如果子问题的规模仍然不够小,则再划分为k个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止。

分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。

 

分治法的三个步骤:(解题步骤类似)

①    Divide(分解问题):把原问题分解成若干个余原问题性质相类似的子问题

②    Conquer(求解子问题):不断分解子问题直到方便求出子问题的解为止

③    Combine(合并子问题)/(Merge):合并子问题的解得到原问题的解。

 

 

分治法适用的情况:

分治法所能解决的问题一般具有以下几个特征:

 

    1) 该问题的规模缩小到一定的程度就可以容易地解决

 

    2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。

 

    3) 利用该问题分解出的子问题的解可以合并为该问题的解;

 

    4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

 

第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;

 

第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归思想的应用;、

 

第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。

 

第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好

(参考博客:https://blog.csdn.net/effective_coder/article/details/8697789

 

 

 

                                                                                                          结对编程的报告

 

以课上的算法题为例子:

7-1 最大子列和问题 (20分)

给定K个整数组成的序列{ N​1​​, N​2​​, ..., NK​​ },“连续子列”被定义为{ Ni​​, Ni+1​​, ..., Nj​​ },其中 1≤ijK。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。

本题旨在测试各种不同的算法在各种数据情况下的表现。各组测试数据特点如下:

  • 数据1:与样例等价,测试基本正确性;
  • 数据2:102个随机整数;
  • 数据3:103个随机整数;
  • 数据4:104个随机整数;
  • 数据5:105个随机整数;

输入格式:

输入第1行给出正整数K (≤100000);第2行给出K个整数,其间以空格分隔。

输出格式:

在一行中输出最大子列和。如果序列中所有整数皆为负数,则输出0。

 

设计思想:

 

我个人的体会是:分治法光看概念以及听老师的讲解,有种高深莫测的感觉,但是应用起来的感觉很熟悉,有种我们生活中分类的感觉,分治法还可以应用在很多的方面,也许是现在接触的题目比较少,分治法在我的认知里面暂时还是分类讨论,希望随着认识的题目越多,对分治法有更深的认识。

 

代码:#include <iostream>

using namespace std;

int start (int a[],int left,int right){

       int sum =0;

       if(left==right){

              if(a[left>=0])  sum=a[left];

              else sum=0;

       }

       else{

              int mid=(left+right)*0.5;

              int leftnum=start(a,left,mid);

              int rightnum=start(a,mid+1,right);

              int r,g,tool;

              r=tool=0;

              for(int i=mid;i>=left;i--){

                     tool=tool+a[i];

                     if(tool>=r)     r=tool;

              }

              g=tool=0;

              for(int j=mid+1;j<=right;j++){

                     tool=tool+a[j];

                     if(tool>=g)    g=tool;

              }

              sum=r+g;

              if(leftnum>=sum) sum=leftnum;

              if(rightnum>=sum)      sum=rightnum;

       }

       return sum;

}

int main(){

       int n,s;

       int a[1000000];

       cin>>n;

       for(int i=0;i<n;i++){

              cin>>a[i];

       }

       s=start(a,0,n-1);

       cout<<s;

       return 0;

}

 

我们队3人,有一个因为生病的原因无法上课和我们一起做这个题目,我们在宿舍进行了讨论:

 

posted @ 2020-10-03 23:55  JJH-Y  阅读(174)  评论(0编辑  收藏  举报