分治法思想
将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解.
分治模式在每层递归时都有三个步骤:
分解原问题为若干子问题,这些子问题是原问题的规模较小的实例;
解决这些子问题,递归地求解各个子问题,然而,若子问题的规模足够小,则直接求解
合并这些子问题的解成原问题的解.
例子:
归并排序.
排序的一种方法,递归地把数组分成两部分,即为分解,当数组只有一个元素或0个元素,就解决了这个小问题,然后再合并两个数组.搞定!
View Code
逆序对.
数组中下标小但是数值大的即为.递归地分解为左右两半部分,结果就是所有在左边的和所有在右边的和大的在左边小的在右边的和
View Code
一个最大子序列
即一个数组中连续的序列中和最大的,这三个都特别相似.递归分解,要不在左边,要不在右边,要不横跨左右.
View Code
/*分治法---一个最大子序列*/ #include <stdio.h> #define MAXLEN 1000 int arr[MAXLEN]; int Max_Sub_Sum(int a[],int s,int e); //传进数组的指针和起始,终止下标,返回最大子序列的值 int Max_Crossing_Sum(int a[],int s,int m,int e); //最大为a[]中一部分在下标为[s...m]中,一部分下标在[m+1...e]中的拼接 int main(void) { int temp,len=0; while (scanf_s("%d",&temp)!=EOF) { arr[len++]=temp; } puts("输入如下:"); for (int i=0;i<len;i++) { printf("%d ",arr[i]); } putchar('\n'); printf("一个最大子序列为:%d ",Max_Sub_Sum(arr,0,len-1)); getchar(); return 0; } int Max_Sub_Sum(int arrtemp[],int s,int e) //当然,传进来的s是不会大于e的,即 s<=e { if (s<e) //这里至少有两个元素 { int m=(s+e)/2; int MaxLeft=Max_Sub_Sum(arrtemp,s,m); //都在左边 int MaxRight=Max_Sub_Sum(arrtemp,m+1,e); //都在右边 int MaxTwoParts=Max_Crossing_Sum(arrtemp,s,m,e); //横跨左右 if (MaxLeft>=MaxRight&&MaxLeft>=MaxTwoParts) { return MaxLeft; } else if (MaxRight>=MaxLeft&&MaxRight>=MaxTwoParts) { return MaxRight; } else { return MaxTwoParts; } } else //如果两个相等,则只有一个元素,当然就是它了 { return arrtemp[s]; } } int Max_Crossing_Sum(int arrtemp[],int s,int m,int e) //[s...m]和[m+1...e],这里就暴力求解了,这里每个数组至少一个元素 { int len1=m-s+1; int len2=e-m; int maxSum=0; int maxLeft=0,leftTemp=0; for (int i=m;i>=s;i--) //左边最大 { leftTemp+=arrtemp[i]; if (leftTemp>maxLeft) { maxLeft=leftTemp; } } int maxRight=0,rightTemp=0; for (int i=m+1;i<=e;i++) { rightTemp+=arrtemp[i]; if (rightTemp>maxRight) { maxRight=rightTemp; } } return maxLeft+maxRight; }