博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单的分治策略
阅读量:4112 次
发布时间:2019-05-25

本文共 3287 字,大约阅读时间需要 10 分钟。

简单的分治策略

 

分治,是编程中常用的一种策略,例如在归并排序中就有使用。分治策略是一种递归求解问题的方法,在每层的递归中可分为三个步骤:分解(divide)解决(conquer)合并(combine)分解(divide)指的是将问题划分为一些子问题,子问题与原问题具有相同的形式,但规模较之更小。解决(conquer)指的是递归的求解子问题,当问题规模足够小时,直接求解并开始回溯。合并(combine)指的是将子问题得到的解进行合并。在问题规模较大,需要递归求解的时候称之为递归情况(recursive case),子问题规模足够小时,出现“触底”时,就进入了可直接解决的基本情况(base case)

下面分析利用分治策略处理区域内峰值问题的简单例子:求数组的最大子数组之和

假定有一个整型数组Arr[low~high](为了简化过程,使用简单数据类型加以介绍,并且规定该数组中元素数量不低于1个,不大于1000个),现需求出该数组中的一个和最大的子数组以及它的和值。现在我们进行简单分析,要得到该子数组,我们需要知道它在原数组中的边界。原数组可能可以划分出一个或一个以上的子数组,而和最大便成了我们找寻的依据。

       对问题进行分解,假定Arr[i~j]是我们要求的数组,那么原问题可以分成规模更小的问题,完全位于子数组Arr[low~mid]完全位于子数组Arr[mid+1~high] ,跨越中点mid(mid的值为(low+high)/2)。得到了规模更小的问题后,我们就可以对完全位于子数组Arr[low~mid]完全位于子数组Arr[mid+1~high]这两个规模更小的问题进行递归求解了。然后我们只需要对跨越中点mid这种情况在单独处理下,我们就能够得到每层递归中的子问题的解了,然后再对子问题的解合并,当然这里并不是意味着相加,而是依据我们的条件选择和处理。

       现在对子问题进行处理流程分析。先从特殊的情况开始:

              1、计算low到mid范围内的和值,记为左最大和值。

              2、计算mid+1到high范围内的和值,记为右最大和值。

3、计算左最大和右最大的和,记为跨越中点最大和值。

       然后是完全位于子数组Arr[low~mid]完全位于子数组Arr[mid+1~high]这两种情况,实际上这是处理上等同的情况,因为我们只需要同原问题一样分解处理直到触底发生。所以我们需要:

1、 先判断触底是否发生,触底情况为low和high相等,此时只有一个元素,和值就为该元素本身。

2、 获取左最大

3、 获取右最大

4、 获取跨越中点最大

5、 合并处理三个最大,得到符合条件的子数组和它的和值。

 

下面给出该问题的C语言主要源码:

#include
#include
typedefstruct data{ int left; int right; long long int sum;}Data; voidfindCrossSubArr(long int *arr,int low,int mid,int high,Data *crossResult){ long long int left_sum=INT_MIN; // INT_MIN, C标准中定义的最小数 long long int right_sum=INT_MIN; long long int sum=0; int I, j; //左 for(i=mid;i>=low;i--) { sum=sum+arr[i]; if(sum>left_sum) { left_sum=sum; crossResult->left=i; } } //右 sum=0; for(j=mid+1;j<=high;j++) { sum=sum+arr[j]; if(sum>right_sum) { right_sum=sum; crossResult->right=j; } } crossResult->sum=left_sum+right_sum; retutn ;} voidfindMaxSubArr(long int *arr,int low,int high,Data *result){ Data leftResult,rightResult,crossResult; int mid=(low+high)/2; //除以2 // 触底情况处理 if(low==high) //只有一个元素 { result->left=low; result->right=low; result->sum=arr[low]; return; } //分解、解决部分 findMaxSubArr(arr,low,mid,&leftResult); // 左 findMaxSubArr(arr,mid+1,high,&rightResult); // 右 findCrossSubArr(arr,low,mid,high,&crossResult); // 跨越中点 // 合并处理部分 // 左 if((leftResult.sum)>=(rightResult.sum)&&(leftResult.sum)>=(crossResult.sum)) { result->left=leftResult.left; result->right=leftResult.right; result->sum=leftResult.sum; return ; } // 右 elseif((rightResult.sum)>=(leftResult.sum)&&(rightResult.sum)>=(crossResult.sum)) { result->left=rightResult.left; result->right=rightResult.right; result->sum=rightResult.sum; return ; } // 跨越中点 else { result->left=crossResult.left; result->right=crossResult.right; result->sum=crossResult.sum; return ; } } intmain(void){ Data result; long int arr[]; // 此处添加输入数据代码》》》》 findMaxSubArr(arr,low,high,&result); // 此处添加结果输出代码》》》》 return 0;}

转载地址:http://tmmsi.baihongyu.com/

你可能感兴趣的文章
new与delete
查看>>
线索二叉树
查看>>
外部排序 归并排序
查看>>
POJ 3255 Roadblocks 最短路Dijkstra+堆优化
查看>>
poj 3723 最大生成树
查看>>
poj 2139 Six Degrees of Cowvin Bacon 最短路bellman 多源最短路径 (一次AC)
查看>>
Codeforces Round #329 (Div. 2) A. 2Char 字符串+暴力
查看>>
poj 3259 Wormholes 最短路bellman 题意转化很重要
查看>>
poj 2456 Aggressive cows 整数二分写法 模板题
查看>>
poj 3104 Drying 二分搜索--查找最小yes值
查看>>
poj 3111 K Best 二分搜索 最大化平均值
查看>>
POj 3258 River Hopscotch 二分搜索 最大化最小值
查看>>
poj 2674 Linear world 弹性碰撞 升级的蚂蚁
查看>>
poj 2785 4 Values whose Sum is 0
查看>>
Codeforces Round #324 (Div. 2) A. Olesya and Rodion 构造数字 思维题
查看>>
Codeforces Round #324 (Div. 2) B. Kolya and Tanya 思维题 数论
查看>>
Poj 3977 Subset 折半枚举 超大背包
查看>>
poj 2549 Sumsets 折半枚举
查看>>
poj 3276 Face The Right Way 挑战150 反转
查看>>
poj 3279 Fliptile 反转
查看>>