分治法是建基于多项分支递归的一种很重要的算法范式。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解就是子问题的解的合并。
一、分治法应用的条件
1.该问题的规模缩小到一定的程度就可以容易地解决
2.该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
3.利用该问题分解出的子问题的解可以合并为该问题的解;
4.该问题所分解出的各个子问题是相互的,即子问题之间不包含公共的子问题。
二、分治法应用的一般步骤
1.分解。将原问题分解为若干个相互,规模小,与原问题相识的子问题。 2.求解子问题。容易求出若干个子问题的解,如果不能,则继续分解子问题,直到能够快速求解为止。
3.合并。将已求的各子问题的解,合并为原问题的解。
三、分析分治法在安排循环赛中的应用
1.问题描述:
设有n位选手参加羽毛球循环赛,循环赛共进行n-1天,每位选手要与其他n-1位选手比赛一场,且每位选手每天比赛一场,不能轮空,按一下要求为比赛安排日程,
(1) 每位选手必须与其他n-1格选手格赛一场; (2) 每个选手每天只能赛一场; (3) 循环赛一共进行n-1天; 2.算法分析:
此算法设计中,对于n为2的幂次方时,较为简单,可以运用分治法,将参赛选手分成两部分,再继续递归分割,直到只剩下2位选手比赛就可以的。再逐步合并子问题即可求得原问题的解。 算法设计如下:
void arrangement(int n,int N,int k,int a[100][100]) // n为参赛人数,N为天数,k为幂次数 {
for(int i=1;i<=N;i++) a[1][i] = i; int m =1;
for (int s=1;s<=k;s++) {
N/=2;
for(int t=1;t<=N;t++)
{ for(int i=m+1;i<=2*m;i++) for(int j=m+1;j<=2*m;j++)
{ a[i][j+(t-1)*m*2]=a[i-m][j+(t-1)*m*2-m]; //右下角的值等于左上角的值
a[i][j+(t-1)*m*2-m]=a[i-m][j+(t-1)*m*2]; //左下角的值等于右上角的值 } } m *= 2;
} }
在此算法中,先是对一个参赛人员进行安排,然后定义一个初始化值为1的m来控制每一次填充表格时i(i表示行)和j(j表示列)的起始填充位置,用一个for循环将原问题分成几个部分,再用一个for循环对每个部分进行划分。最后根据划分和分治法的思想,进行对角线的填充。
简单的的说就是先对一个人的安排,扩充到2个人,再是4个人等等,由比赛规则,确定的,一人一天只能比赛一场,因此两人的比赛安排在一天中是对角形式的。
分析算法的时间性能,迭代处理的循环体内是2个循环语句,基本的语句是赋值,也就是填写比赛日程表中的元素,基本的语句执行次数为:
T(n)= =O( )
当n为是奇数时,至少举行n 轮比赛,这时每轮必有一支球队轮空。为了统一奇数偶数的不一致性,当n 为奇数时, 可以加入第n+1 支球队( 虚拟球队, 实际上不存在) , 并按n+1 支球队参加比赛的情形安排比赛日程。那么n( n 为奇数) 支球队时的比赛日程安排和n+1 支球队时的比赛日程安排是一样的。只不过每次和n+1 队比赛的球队都轮空。所以,我们只需考虑n 为偶数时情况。将最后得出的结果,对n+1进行赋予0的操作就可以的。并且把对n+1参赛人员的安排进行赋0操作 例如:当n=3
1 2 3 4 1 2 3 0 2 3 4 1 4 3 4 1 2 3 2 1 2 3 0 1 0 0 0 1 0 3 2 0 因此对算法进行改进,把第m号虚的选手去掉(换做0) void replaceVirtual(int m) {
int i,j;
for(i=0;i a[i][j] = (a[i][j]==m)?0:a [i][j]; } return; } 但当n为偶数时,而n/2却为奇数时,递归返回的轮空的比赛要作进一步处理。可以在前n/2 轮比赛中让轮空选手与下一个未参赛选手进行比赛。 算法设计: void copyodd(int m) { int i,j; for (j=0;j<=m;j++) //1. 求第2组的安排(前m天) { for (i=0;i a[i+m][j]=a[i][j]+m; } else //特殊处理:两个队各有一名选手有空,安排他们比赛 { a[i+m][j] = i+1; a[i][j] = i+m+1; } } } for(i=0,j=m+1;j<2*m;j++) { a[i][j] = j+1; //2. 1号选手的后m-1天比赛 a[ (A[i][j] -1) ][j] = i+1; //3. 他的对手后m-1天的安排 } for (i=1;i {//2. 观察得到的规则一:向下m+1~2*m循环递增 A[i][j] = ((A[i-1][j]+1)%m==0)?A[i-1][j]+1 :m + (A[i-1][j]+1)%m; //3. 对应第2组的对手也要做相应的安排 A[ (A[i][j]-1) ][j] = i+1; } } return; } 3.算法时间复杂度分析: 当n/2为奇数时,迭代处理的循环体内部有2个循环结构,基本语句是循 环体内的赋值语句,即填写比赛日程表中的元素。基本语句的执行次数是: T(n)= =O( ) 此时时间复杂度为0( )。 因此,总体实现的算法复杂度为O( ) 4.整体程序运行结果及其分析: 当n为3时 在上面n为3时就出现了n/2为奇数,因此在分组时,会出现空选选手,因此对其进行加1,使之成为偶数,并在最后对此添加的偶数进行0的替换。 当输入的n为7,8时有: 比较上面两个不同参赛人数的比赛安排,你会发现其实他们没有什么本质的差别,当n为8时符合2的整数次幂,因此刚好安排,不留空选,但当n为7时,为奇数,需要做加1操作,当它做加1操作完后,符合2的整数次幂,因此在最后的赋0操作中将号码为8的赋以0,并且去除8的比赛,因此会发现当n为7或者n为8时,结果是很相似的。 而且从程序的设计,和比较上分析,可以明显的感觉到当n=8比n=7,程序所执行的要少,为此,修改一下,使之能够检测出,从程序运行开始到程序结束所花费的时间。 在相同的环境下运行结果 虽然每次运行的时间不同,但都是n=8运行的时间比n=7运行的时间少。 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- fupindai.com 版权所有 赣ICP备2024042792号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务