算法学习(一)分治算法

算法学习(一)分治算法

1.1 引言

   当我们在处理一些问题时,由于这些问题要处理的数据很多,或者求解的过程很复杂,这时如果直接求解将会在时间上花费很长时间,或者根本没办法求出,对于这一类的问题,我们可以先把它分解为几个子问题,找到并求出这些子问题的相应的解,然后再用适当的方法将他们组合成整个问题的解,这种问题处理的方式,我们就把它叫做分治法。

1.2 算法思路

 (1)分解:将要求解的问题划分成若干规模较小的同类问题;

  (2)求解:当子问题划分的足够小时,用较简单的方法解决;

  (3)合并:按求解问题的要求,将子问题的解进行逐层合并,即可构成最终的解;

1.3 实例:乒乓比赛赛程安排

 设有n=2的k次方个运动员要进行网球循环赛。现要设计一个满足以上要求的比赛日程表:

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

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

  (3)循环赛一共进行n-1天;

    按照分治策略,可以将所有选手对分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归的用这种一分为二的策略对选手进行分隔,直到剩下两个选手时,比赛日程表的制定就变得简单了,这时只让这两个选手进行比赛就可以了。

    (由于楼主不会发图上传,请各位看官们包涵辣)

    对于8个选手的比赛日程表,其中左上角的与左下角的两小块分别为选手1至选手4和选手5至选手8前三天的比赛日程。据此,将左上角小块中的所有数字按其相对位置抄到右下角,将左下角小块的所有数字按其相对位置抄到右上角,这样就分别安排好了选手从1到选手4和选手5到选手8在后四天的比赛日程!(最重要的就是这个步骤的实现)

    下面附上代码:

    

<span style="font-size:18px;">#include <stdio.h>
#include <conio.h>
#define MaxN 64 //表示最多可安排64位选手来参加比赛 
int a[MaxN+1][MaxN+1]={0}; 
//定义的时候为最大数加一,表示不安排第0号元素参与运算 
void gamecal(int k,int n)//处理编号k开始的n个选手的日程
{ /*
	1.k表示需要安排的选手的起始序号 
        2.n表示需要安排的选手的数量 ;
  	3.k=1,n=4表示从1号选手开始安排四位选手的日程
	  k=3,n=2表示从3号选手开始安排两位选手的日程 
  */
	int i,j;
	if(n==2)
	{
	  a[k][1]=k;//参赛选手编号
	  a[k][2]=k+1;//对阵选手编号
	  a[k+1][1]=k+1;//参赛选手编号
	  a[k+1][2]=k;//对阵选手编号	
	}else{
		gamecal(k,n/2); //首先将其分成两半 
		gamecal(k+n/2,n/2); 
		//接下来就是合并的问题 
		for(i=k;i<k+n/2;i++)//填充右上角
		{   //把左下角的填充到右上角 
			for(j=n/2+1;j<=n;j++)
			{
				a[i][j]=a[i+n/2][j-n/2];
			}
		} 
		for(i=k+n/2;i<k+n;i++) //填充右下角
		{   //把左上角的填充到右下角 
			for(j=n/2+1;j<=n;j++)
			{
				a[i][j]=a[i-n/2][j-n/2];
			}
		} 
	}
} 

int main()
{
	int m,i,j;
	printf("输入参赛选手的人数:");
	scanf("%d",&m);
	j=2;
	for(i=2;i<8;i++)
	{
		j=j*2;
		if(j==m) break;	
	}	
	if(i>=8)
	{
		printf("参赛选手人数必须为2的整数次幂,且不超过64! \n");
		getch();
		return 0;
	}
	gamecal(1,m);
	printf("\n编号 ");
	for(i=2;i<=m;i++)
	   printf("%2d天",i-1);
	printf("\n");
	for(i=1;i<=m;i++)
	{
		for(j=1;j<=m;j++)
			printf("%4d",a[i][j]);
		printf("\n");
	}
	getch();
	return 0;
}</span>
       在这里,因为分治算法还涉及到棋盘覆盖类似于这种的一些问题,楼主有时间会对此进行修改,并将相关问题附录上去,不对的话欢迎拍砖~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

精神抖擞王大鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值