算法实验报告 -- 分治法
金砖问题研究探讨
组员:胡昌腾、刘全成、马起、卢东平、马悦
问题描述:
有一个老板有一袋金块。每个月将有两名雇员会因其优异的表现分别被奖励一个金块。按规矩,排名第
一的雇员将得到袋中最重的金块,排名第二的雇员将得到袋中最轻的金块。根据这种方式,除非有新的金
块加入袋中,否则第一名雇员所得到的金块总是比第二名雇员所得到的金块重。如果有新的金块周期性的
加入袋中,则每个月都必须找出最轻和最重的金块。假设有一台比较重量的仪器,我们希望用最少的比较
次数找出最轻和最重的金块
算法思想:
分而治之方法与软件设计的模块化方法非常相似。为了解决一个大的问题,可以: 1) 把它分成两个
或多个更小的问题; 2) 分别解决每个小问题; 3) 把各小问题的解答组合起来,即可得到原问题的解答。
小问题通常与原问题相似,可以递归地使用分而治之策略来解决。
问题分析:
一般思路
:假设袋中有n 个金块。可以用函数M a x(程序1 - 3 1)通过n-1次比较找到最重的金
块。找到最重的金块后,可以从余下的n-1个金块中用类似的方法通过n-2次比较找出最轻的金块。这的
比较的总次数为2n-3。
分治法:
当n很小时,比如说, n≤2,识别出最重和最轻的金块,一次比较就足够了。当n 较大时
(n>2),第一步,把这袋金块平分成两个小袋A和B。第二步,分别找出在A和B中最重和最轻的金块。
设A中最重和最轻的金块分别为HA 与LA,以此类推,B中最重和最轻的金块分别为HB 和LB。第三步,
通过比较HA 和HB,可以找到所有金块中最重的;通过比较LA 和LB,可以找到所有金块中最轻的。在
第二步中,若n>2,则递归地应用分而治之方法
算法实现:
截图:
输入5块金块的重量后:
得出的结果为
源代码:
#include
using namespace std;
int a[5]={10,12,5,9,7};
void maxmin(int i,int j, int &max,int &min )
{
int mid;
int lmax,lmin,rmax,rmin;
if(i==j)
{
max=a[i];
min=a[j];
}
else if(i==j-1)
if(a[i]{
max=a[j];
min=a[i];
}
else {max=a[i];
min=a[j];}
else{
mid=(i+j)/2;
maxmin(i,mid,lmax,lmin);
maxmin(mid+1,j,rmax,rmin);
if(lmax>rmax)
max=lmax;
else
max=rmax;
if(lmin>rmin)
min=rmin;
else
min=lmin;
}
}
void main()
{ //给数组赋值
int *p=a;
cout<<"*******************************"<
{
cout<<"请输入第"<
}
for(int m=0;m<5;m++)
{
cout<<"第"< } template if (w[i] > w[i+1]) {
int max,min;
maxmin(0,4,max,min);
cout<<"重量最大为"<
复杂性分析
注意到当n为偶数时,在for 循环外部将执行一次比较而在f o r循环内部执行3 ( n / 2 - 1 )次比较,
比较的总次数为3 n / 2 - 2。当n 为奇数时,f o r循环外部没有执行比较,而内部执行了3(n-1)/2次比较。
因此无论n 为奇数或偶数,当n>0时,比较的总次数为「3n/2ù-2次。
关键步骤:
程序14-1 找出最小值和最大值的非递归程序
bool MinMax(T w[], int n, T& Min, T& Max)
{// 寻找w [ 0 : n - 1 ]中的最小和最大值
// 如果少于一个元素,则返回f a l s e
// 特殊情形: n <= 1
if (n < 1) return false;
if (n == 1) {Min = Max = 0;
return true;}
/ /对Min 和M a x进行初始化
int s; // 循环起点
if (n % 2) {// n 为奇数
Min = Max = 0;
s = 1;}
else {// n为偶数,比较第一对
if (w[0] > w[1]) {
Min = 1;
Max = 0;}
else {Min = 0;
Max = 1;}
s = 2;}
// 比较余下的数对
for (int i = s; i < n; i += 2) {
// 寻找w[i] 和w [ i + 1 ]中的较大者 // 然后将较大者与w [ M a x ]进行比较 // 将较小者与w [ M i n ]
进行比较
if (w[i] > w[Max]) Max = i;
if (w[i+1] < w[Min]) Min = i + 1;}
else {
if (w[i+1] > w[Max]) Max = i + 1;
if (w[i] < w[Min]) Min = i;}
}
return true; }
C++分治法求最值
题目来源:□教材页题□教师补充□自选题目
主要功能描述:
(1)对一组数进行比较大小,求出其中的最大值和最小值,利用分治法的原理来实现。
(2)先对数组中元素个数进行判断,只有一个元素时,最大值max和最小值min都是它本身;当有两个元素时,比较两个数的大小,大者为最大值max,小者为最小值min;当数组中元素多于两个时,里用分治法原理,递归调用MaxMin函数,求出划分出的每组中的最值与另外一组最值比较,最后的得出最大值max和最小值min。
{
return maxSize;
}
void InputArray()//输入数组中元素
{
int i;
for(i=0;i<maxSize;i++)
{
cout<<"请输入"<<(i+1)<<"个元素:";
cin>>array[i];
}
}
void dispayAΒιβλιοθήκη ray()//输出数组中元素{
int i;
int maxSize;//定义数组长度
public:
SortableList(){};
void SetMaxSize()
{
cout<<"请输入数组中元素个数:";
cin>>maxSize;//输入数组长度
array=new T[maxSize];//定义存储空间
}
int GetMaxSize()//返回数组长度
if(max<max1)max=max1;//两表中最大元的大者为原表最大元
分治算法设计(求第K个最小数)
福建工程学院计算机与信息科学系实验报告2010 – 2011 学年第一学期任课老师:实验题目1.设计程序利用分治策略求n个数的最大值和最小值。
2.利用分治策略,在n个不同元素中找出第k个最小元素。
实验时间实验开始日期:报告提交日期:实验目的、要求一、算法设计技术当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出。
对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法。
如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。
这就是分治策略的基本思想。
下面通过实例加以说明。
【例】在n个元素中找出最大元素和最小元素。
我们可以把这n个元素放在一个数组中,用直接比较法求出。
算法如下:void maxmin1(int A[],int n,int *max,int *min){ int i;*min=*max=A[0];for(i=2;i < n;i++){ if(A[i] > *max) *max= A[i];if(A[i] < *min) *min= A[i];}}上面这个算法需比较2(n-1)次。
能否找到更好的算法呢?我们用分治策略来讨论。
把n个元素分成两组:A1={A[1],...,A[int(n/2)]}和A2={A[int(N/2)+1],...,A[N]}分别求这两组的最大值和最小值,然后分别将这两组的最大值和最小值相比较,求出全部元素的最大值和最小值。
如果A1和A2中的元素多于两个,则再用上述方法各分为两个子集。
直至子集中元素至多两个元素为止。
例如有下面一组元素:-13,13,9,-5,7,23,0,15。
用分治策略比较的过程如下:图中每个方框中,左边是最小值,右边是最大值。
从图中看出,用这种方法一共比较了10次,比直接比较法的14次减少4次,即约减少了1/3。
分治算法
65 97
13 76
38 49 65 97
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归 调用
49 38 65 97 76 13 27
38 49
65 97
13 76
27
38 49 65 97
题的解,自底向上逐步求出原来问题的解。
T(n)
=
n
递归的概念
由分治法产生的子问题往往是原问题的较小模式,这 就为使用递归技术提供了方便。在这种情况下,反复 应用分治手段,可以使子问题与原问题类型一致而其 规模却不断缩小,最终使子问题缩小到很容易直接求 出其解。这自然导致递归过程的产生。
直接或间接地调用自身的算法称为递归算法。用函数 自身给出定义的函数称为递归函数。
黑盒划分典型问题—合并排序
【例5】合并排序
任务描述:任意给定一包含n个整数的集合,把n个整数按升序排列。 输入:每测试用例包括两行,第一行输入整数个数,第二行输入n个整 数,数与数之间用空格隔开。最后一行包含-1,表示输入结束。 输出:每组测试数据的结果输出占一行,输出按升序排列的n个整数。 样例输入:
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归调用 自然合并排序
49 38 65 97 76 13 27
49
38 65 97
76
13 27
38 49 65 97
黑盒划分典型问题—逆序对问题
算法设计与分析实验报告
算法设计与分析实验报告实验一全排列、快速排序【实验目的】1. 掌握全排列的递归算法。
2. 了解快速排序的分治算法思想。
【实验原理】一、全排列全排列的生成算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。
任何n个字符集的排列都可以与1~n的n个数字的排列一一对应,因此在此就以n 个数字的排列为例说明排列的生成法。
n个字符的全体排列之间存在一个确定的线性顺序关系。
所有的排列中除最后一个排列外,都有一个后继;除第一个排列外,都有一个前驱。
每个排列的后继都可以从它的前驱经过最少的变化而得到,全排列的生成算法就是从第一个排列开始逐个生成所有的排列的方法。
二、快速排序快速排序(Quicksort)是对冒泡排序的一种改进。
它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
【实验内容】1.全排列递归算法的实现。
2.快速排序分治算法的实现。
【实验结果】1. 全排列:2. 快速排序:实验二最长公共子序列、活动安排问题【实验目的】1. 了解动态规划算法设计思想,运用动态规划算法实现最长公共子序列问题。
2. 了解贪心算法思想,运用贪心算法设计思想实现活动安排问题。
【实验原理】一、动态规划法解最长公共子序列设序列X=和Y=的一个最长公共子序列Z=,则:i. 若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;ii. 若xm≠yn且zk≠xm ,则Z是Xm-1和Y的最长公共子序列;iii. 若xm≠yn且z k≠yn ,则Z是X和Yn-1的最长公共子序列。
其中Xm-1=,Yn-1=,Zk-1=。
最长公共子序列问题具有最优子结构性质。
由最长公共子序列问题的最优子结构性质可知,要找出X=和Y=的最长公共子序列,可按以下方式递归地进行:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得X和Y的一个最长公共子序列。
算法之2章递归与分治
算法分析(第二章):递归与分治法一、递归的概念知识再现:等比数列求和公式:1、定义:直接或间接地调用自身的算法称为递归算法。
用函数自身给出定义的函数称为递归函数。
2、与分治法的关系:由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。
在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。
这自然导致递归过程的产生。
分治与递归经常同时应用在算法设计之中,并由此产生许多高效算法。
3、递推方程:(1)定义:设序列01,....na a a简记为{na},把n a与某些个()ia i n<联系起来的等式叫做关于该序列的递推方程。
(2)求解:给定关于序列{n a}的递推方程和若干初值,计算n a。
4、应用:阶乘函数、Fibonacci数列、Hanoi塔问题、插入排序5、优缺点:优点:结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性,因此它为设计算法、调试程序带来很大方便。
缺点:递归算法的运行效率较低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多。
二、递归算法改进:1、迭代法:(1)不断用递推方程的右部替代左部(2)每一次替换,随着n的降低在和式中多出一项(3)直到出现初值以后停止迭代(4)将初值代入并对和式求和(5)可用数学归纳法验证解的正确性2、举例:-----------Hanoi塔算法----------- ---------------插入排序算法----------- ()2(1)1(1)1T n T nT=−+=()(1)1W n W n nW=−+−(1)=021n-23()2(1)12[2(2)1]12(2)21...2++2 (121)n n n T n T n T n T n T −−=−+=−++=−++==++=−(1)2 ()(1)1((n-2)+11)1(2)(2)(1)...(1)12...(2)(1)(1)/2W n W n n W n n W n n n W n n n n =−+−=−−+−=−+−+−==++++−+−=−3、换元迭代:(1)将对n 的递推式换成对其他变元k 的递推式 (2)对k 进行迭代(3)将解(关于k 的函数)转换成关于n 的函数4、举例:---------------二分归并排序---------------()2(/2)1W n W n n W =+−(1)=0(1)换元:假设2kn =,递推方程如下()2(/2)1W n W n n W =+−(1)=0 → 1(2)2(2)21k k k W W W−=+−(0)=0(2)迭代求解:12122222321332133212()2(2)212(2(2)21)212(2)22212(2)2*2212(2(2)21)2212(2)222212(2)3*2221...2(0)*2(22...21)22k k k k k k k k k k k k k k k k k k k k k k k k W n W W W W W W W W k k −−−−−−−+−+−−−=+−=+−+−=+−+−=+−−=+−+−−=+−+−−=+−−−==+−++++=−1log 1n n n +=−+(3)解的正确性—归纳验证: 证明递推方程的解是()(1)/2W n n n =−()(1)1W n W n n W =−+−(1)=0,(n 1)=n +n=n(n-1)/2+n =n[(n-1)/2+1]=n(n+1)/2n W W +方法:数学归纳法证 n=1,W(1)=1*(1-1)/2=0假设对于解满足方程,则()---------------快速排序--------------------->>>平均工作量:假设首元素排好序在每个位置是等概率的112()()()(1)0n i T n T i O n n T −==+=∑ >>>对于高阶方程应该先化简,然后迭代(1)差消化简:利用两个方程相减,将右边的项尽可能消去,以达到降阶的目的。
算法的技术手段范文
算法的技术手段范文下面将介绍一些常见的算法的技术手段。
1.分治法分治法将问题划分为若干个规模较小的子问题,然后分别解决这些子问题,最后将各个子问题的解合并得到原问题的解。
这种技术手段在快速排序和归并排序等算法中有广泛的应用。
2.动态规划动态规划将问题划分为多个阶段,根据问题的最优子结构特性,将其解决过程划分为多个阶段的决策过程。
动态规划算法通常需要使用递归和数组的结构来存储中间计算结果,以避免重复计算。
背包问题、最短路径问题等都可以使用动态规划算法来解决。
3.贪心法贪心法在每一步都选择当前最优解,然后继续向下一步迭代,直到得到最终解。
贪心法通常快速且简单,但不能保证得到全局最优解,有时只能得到近似解。
经典的贪心算法有霍夫曼编码和最小生成树算法等。
4.回溯法回溯法通过不断尝试和回溯来达到求解问题的目的。
在过程中,若当前路径不能满足问题的条件,就退回到上一步重新选择路径。
回溯法广泛应用于解决组合、排列、图的遍历等问题。
5.枚举法枚举法是穷举所有可能的解,然后从中选择最优解的一种方法。
枚举法常用于求解排列、组合等问题。
虽然在大规模问题上效率较低,但是在规模较小的问题上,可以得到精确的解。
6.分支限界法分支限界法通过不断扩展最优解的空间,并用界限函数排除不可能达到最优解的部分空间,从而提高算法的效率。
分支限界法常用于解决最优化问题,如旅行商问题、0-1背包问题等。
7.近似算法近似算法是用于求解NP难问题的一种方法,通过折中计算精确性和效率,给出一个近似解。
近似算法的设计思路包括贪心法、局部、随机化等。
近似算法不保证得到全局最优解,但可以在多项式时间内给出一个接近最优解的解。
8.随机算法随机算法利用随机数的性质来解决问题,通过随机挑选可能的解进行,以期望找到一个满足条件的解。
随机算法通常用于解决优化问题,如模拟退火算法和遗传算法等。
总之,算法的技术手段是多种多样的,通过合理的选择和组合,可以提高算法的效率和准确性。
分治算法求解二维点集合的skyline
分治算法求解二维点集合的skyline分治算法(Divide and Conquer)是一种常见的算法设计思想,通过将问题划分成多个子问题并分别解决,最后合并子问题的解来得到原问题的解。
在求解二维点集合的skyline问题时,可以使用分治算法来提高算法效率。
二维点集合的skyline问题可以描述如下:给定一组二维点的集合,求解在x轴上没有点的水平线上的点集,即skyline。
其中,水平线上的点的y坐标不得大于当前水平线上的所有点中的最大y坐标。
下面介绍如何使用分治算法来求解二维点集合的skyline问题:1. 将点集合按照x轴坐标进行排序。
可以使用快速排序等算法对点集合进行排序。
2. 将排序后的点集合分成两个子问题。
可以按照点集合的中间点将集合一分为二。
假设中间点的x坐标为x_mid,将点集合分为两个子集合:左集合L和右集合R,其中L中的点的x坐标小于等于x_mid,R中的点的x坐标大于x_mid。
3. 对左右两个子集合分别递归地求解skyline。
即对子集合L和R进行调用算法以得到各自的skyline。
4. 合并左右两个子集合的skyline。
将两个skyline合并成一个结果。
合并时,需要比较两个skyline中每个点的y坐标,选取较大的点加入结果中。
如果两个skyline中的点的y坐标相同,则选取左侧的点加入结果中。
通过上述分治算法求解二维点集合的skyline,可以得到正确的结果。
该算法的时间复杂度为O(nlogn)。
其中,n为点集合的大小。
参考内容:- Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). Introduction to Algorithms (3rd Edition). The MIT Press.- Bentley, J. L. (1977). Algorithms for K-Dimensional Quadrant Queries and Orthogonal Range Searching. In Proceedings of the Eighth Annual ACM Symposium on Theory of Computing (pp. 9-16).。
分治算法求解二维极大点问题的求解
分治算法求解二维极大点问题成员分工:(1)源程序文件——李凤媛(2)文档:二维极大点问题描述、分治算法求解二维极大点问题的算法思想、算法描述——蒙慧颖算法实现——李桥秀实验环境、实验结果——马迪文档格式——李乐(3)本课题PPT——刘思志、李乐(4)利用PPT对课题完成情况做介绍——李凤媛一、二维极大点问题的描述在二维空间中,如果X1≥X2且Y1≥Y2,那么称点(X1,Y1)支配点(X2,Y2)。
如果一个点没有其他点支配,那么称其为极大者。
己知有n个点的集合,求极大点问题是指找出在n个点中的所有极大点。
二、分治算法求解二维极大点问题的算法思想通过分治策略来解决二维极大点问题。
首先找出垂直于x轴的中位线L,用它划分整个点集为两个子集,分别用SL和SR表示中线L的左边点集合和右边点集合。
然后分别找出SL和SR的极大点。
找出SL和SR的极大点后将它们合并求出总点集的极大点,由于在SR中点的x值总是大于SL中每个点的x值,所以SR中的极大点合并后仍是极大点,而SL中的极大点需满足y值不小于SR 中极大点的最大y值才是合并后的极大点。
三、算法描述:步骤1:如果S只含一个点,那么输出该点为极大点;否则找一条垂直于x 轴的直线L,它划分点集合为两个子集合SL和SR,每个子集含有n/2个点。
步骤2:递归地找出SL和SR的极大点。
步骤3:将SL和SR的极大点投影到直线L上,并根据它们的y值排序这些点。
对投影进行线性扫描,如果SL中的极大点的y值小于SR中某个极大点的y值,那么舍弃它。
四、算法实现用预排序分治策略求解二维极大点问题,首先定义结构体数组用来保存点的坐标。
使用随机函数、计时函数来生成点的坐标集并记录运行时间。
然后对坐标集按照x值大小进行冒泡排序,并用for循环为SL、SR两个点集赋值,定义printf函数用for循环输出S、SL、SR中点的坐标,再分别递归求出SL、SR的极大点再将极大点输出并记录在集合m中,合并时for循环输出m中SR的极大点,对集合m中SL的极大点按y值大小进行冒泡排序,并输出m中比SR的极大点的最大y值大的SL的极大点。
算法实验3-最大子段和问题实验报告
昆明理工大学信息工程与自动化学院学生实验报告( 2011 — 2012 学年 第 1 学期 )课程名称:算法设计与分析 开课实验室:信自楼机房444 2012 年12月 14日一、上机目的及内容1.上机内容给定有n 个整数(可能有负整数)组成的序列(a 1,a 2,…,a n ),求改序列形如∑=jk ka1的子段和的最大值,当所有整数均为负整数时,其最大子段和为0。
2.上机目的(1)复习数据结构课程的相关知识,实现课程间的平滑过渡; (2)掌握并应用算法的数学分析和后验分析方法;(3)理解这样一个观点:不同的算法能够解决相同的问题,这些算法的解题思路不同,复杂程度不同,解题效率也不同。
二、实验原理及基本技术路线图(方框原理图或程序流程图)(1)分别用蛮力法、分治法和动态规划法设计最大子段和问题的算法; 蛮力法设计原理:利用3个for 的嵌套(实现从第1个数开始计算子段长度为1,2,3…n 的子段和,同理计算出第2个数开始的长度为1,2,3…n-1的子段和,依次类推到第n 个数开始计算的长为1的子段和)和一个if (用来比较大小),将其所有子段的和计算出来并将最大子段和赋值给summax1。
用了3个for 嵌套所以时间复杂性为○(n 3);分治法设计原理:1)、划分:按照平衡子问题的原则,将序列(1a ,2a ,…,na )划分成长度相同的两个字序列(1a ,…,⎣⎦2/n a )和(⎣⎦12/+n a ,…,na )。
2)、求解子问题:对于划分阶段的情况分别的两段可用递归求解,如果最大子段和在两端之间需要分别计算s1=⎣⎦⎣⎦)2/1(max2/n i an ik k≤≤∑=,s2=⎣⎦⎣⎦)2/(max12/n j n ajn k k≤≤∑+=,则s1+s2为最大子段和。
若然只在左边或右边,那就好办了,前者视s1为summax2,后者视s2 o summax2。
3)、合并:比较在划分阶段的3种情况下的最大子段和,取三者之中的较大者为原问题的解。
分治算法(C++版)
//输入排序好的数
//输入要查找的数 //递归过程
//递归过程
//取中间位置点
if (a[k]==m) cout<<"then num in "<<k<<endl; if (x>y) cout<<"no find"<<endl; else { if (a[k]<m) jc(k+1,y); if (a[k]>m) jc(x,k-1); } }
【问题分析】
以M=3(即N=23=8)为例,可以根据问题要求,制定出如下图所示的 一种方案:
以表格的中心为拆分点,将表格分成A、B、C、D四个部分,就很容易看 出有A=D,B=C,并且,这一规律同样适用于各个更小的部分。 设有n个选手的循环比赛,其中n=2m,要求每名选手要与其他n-1名选手 都赛一次。每名选手每天比赛一次,循环赛共进行n-1天。要求每天没有选手 轮空.以下是八名选手时的循环比赛表,表中第一行为八位选手的编号,下面 七行依次是每位选手每天的对手。
【参考程序】 #include<cstdio> const int MAXN=33,MAXM=5; int matchlist[MAXN][MAXN]; int m; int main() { printf("Input m:"); scanf("%d",&m); int n=1<<m,k=1,half=1; // 1<<m 相当于 2^m matchlist[0][0]=1; while (k<=m) { for (int i=0;i<half;i++) //构造右上方方阵 for (int j=0;j<half;j++) matchlist[i][j+half]=matchlist[i][j]+half; for (int i=0;i<half;i++) //对称交换构造下半部分方阵 for (int j=0;j<half;j++) { matchlist[i+half][j]=matchlist[i][j+half]; //左下方方 阵等于右上方方阵 matchlist[i+half][j+half]=matchlist[i][j]; //右下方方 阵等于左上方方阵 }
