分治法:

    思想:将一个难以直接解决的大问题,划分成一些规模较小的子问题,以便各个击破,分而治之。

    求阶过程:(1)划分  (2)求解子问题 (3)合并

启发式规则:

1. 平衡子问题:最好使子问题的规模大致相同。也就是将一个问题划分成大小相等的k个子问题(通常k2),这种使子问题规模大致相等的做法是出自一种平衡(Balancing)子问题的思想,它几乎总是比子问题规模不等的做法要好。

2. 独立子问题各子问题之间相互独立,这涉及到分治法的效率,如果各子问题不是独立的,则分治法需要重复地解公共的子问题。

这里关于递归算法的介绍在上一部分https://blog.csdn.net/qq_43236424/article/details/105557620

1、最大子段和问题

给定由n个整数组成的序列(a1, a2, …, an),最大子段和问题要求该序列形如 算法设计与分析笔记4——分治法

的最大值(1ijn),当序列中所有整数均为负整数时,其最大子段和为0

例如,序列(-20, 11, -4, 13, -5, -2)的最大子段和为:算法设计与分析笔记4——分治法

分析:

按照平衡子问题的原则将子段平均分成两部分。

首先是要进行划分,分为三种情况:整个子段在左半部分;整个子段在右半部分;最大子段跨左半部分和右半部分。

然后第一种和第二种情况可以直接递归求解,最后一种情况要分别求解左半部分s1和右半部s2分然后最后相加得到最大子段和算法设计与分析笔记4——分治法     算法设计与分析笔记4——分治法  

最后比较三种情况得到最大子段和的结果取最大值。

参考代码如下:

#include<bits/stdc++.h>
using namespace std;
int Max_three(int a,int b,int c)
{
    int max=a;
    if(b>max)
        max=b;
    if(c>max)
        max=c;
    return max;
}
int Max_Sum(int a[],int left,int right)
{
    int sum;
    if(left==right)
    {
        if(a[left]>0) sum=a[left];
        else sum=0;
    }
    else
    {
        int middle=(left+right)/2;
        int Left_Sum=Max_Sum(a,left,middle);
        int Right_Sum=Max_Sum(a,middle+1,right);
        int mid_left=0;
        int mid_right=0;
        int tmp=0;
        for(int i=middle;i>=left;i--)
        {
            tmp+=a[i];
            if(tmp>mid_left)
                mid_left=tmp;
        }
        tmp=0;
        for(int j=middle+1;j<=right;j++)
        {
            tmp+=a[j];
            if(tmp>mid_right)
                mid_right=tmp;
        }
        int mid_sum=mid_left+mid_right;
        return Max_three(Left_Sum,Right_Sum,mid_sum);
    }
}
int main()
{
    int a[100];
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];
    int tmp=Max_Sum(a,0,n-1);
    cout<<"MaxSum:"<<tmp;
}
 

 2、循环赛日程安排问题

设有n=2k个选手要进行网球循环赛,要求设计一个满足以下要求的比赛日程表:

1)每个选手必须与其他n-1个选手各赛一次;

2)每个选手一天只能赛一次。

按此要求,可将比赛日程表设计成一个 n n-1列的二维表,其中,第 i 行第 j 列表示和第 i 个选手在第 j 天比赛的选手。       

 分析:

按照分治的策略,可将所有参赛的选手分为两部分,n2k个选手的比赛日程表就可以通过为n/22k-1个选手设计的比赛日程表

来决定。递归地执行这种分割,直到只剩下2个选手只要让这2个选手进行比赛就可以了。

算法设计与分析笔记4——分治法

这个求解过程是自底向上的迭代过程。在每次迭代中,将问题划分为4部分:左上角、左下角、右上角、右下角。这个算法的关键就是找这4部分元素之间的对应关系。

参考代码如下:

      void GameTable(int k, int a[ ][ ])    // n=2k(k≥1)个选手参加比赛,a表示日程安排,下标从1开始
     {
         n=2;       //k=0,2个选手比赛日程可直接求得,即得到左上角元素
         a[1][1]=1; a[1][2]=2;   
         a[2][1]=2; a[2][2]=1;
         for (t=1; t<k; t++)    //迭代处理
         {
        temp=n; n=n*2;   //填左下角元素
        for (i=temp+1; i<=n; i++ )
            for (j=1; j<=temp; j++)
                a[i][j]=a[i-temp][j]+temp;    //左下角元素和左上角元素的对应关系
       for (i=1; i<=temp; i++)       //填右上角元素
           for (j=temp+1; j<=n; j++)
              a[i][j]=a[i+temp][(j+temp)% n];
      for (i=temp+1; i<=n; i++)    //填右下角元素
          for (j=temp+1; j<=n; j++)
             a[i][j]=a[i-temp][j-temp];
    }
}

 

相关文章: