实验一:递归与分治

一、循环赛日程安排

1、实验内容

利用分治算法,编程实现循环赛日程表安排问题,并进行时间复杂性分析;

2、实验分析

1.题目理解
(1)根据已经学得知识,8个人大循环赛需要7天。
(2)当比赛人数为2^k时,可以用分治法,多边形轮转法则可以解决一切输入
2.设计分析
(1)输出循环列表,第一列为选手编号,从第n(n>2)列开始,为第n天的比赛信息。(1,2)位置,存放的是2,则代表,在第一天,一号选手和二号选手比赛。
(2)多边形轮转法思路。当人数为奇数n时,n边形中,处在同一条水平线上的一对点一起比赛,单独一条线上的和中心点比赛。当为偶数时,将一个数放入中心点即可。
(3)代码分析,先设计好第一天的的比赛,后面的轮转做

3、程序代码

(代码多借鉴于网络)

/*循环赛日程*/
/*多边形轮转法*/
#include<iostream>
using namespace std;
int b[20];
int plan[1010][1010];
void lunzhuan(int n) {
	plan[n][1] = n;

	if(n==1) return;

	//判断奇数还是偶数,若是奇数转为偶数
	int m;
	if(n%2==1) m=n;
	else m=n-1;
	//

	for(int i=1; i<=m; i++) {
		//第1列,表示第i个选手
		plan[i][1]=i;
		//b数组用来判断同一水平线
		b[i]=b[m+i]=i+1;
	}
	int k, r;
	//轮转 ,确定那个选手和那个选手比赛
	for(int i = 1; i <= m; i++) {
		//单独一个水平线的选手与中心处选手比赛
		plan[1][i + 1] = b[i];//b[i]=i+1,例(1,2)位置放2,1号选手与2号选手在第一天比赛 
		plan[b[i]][i + 1] = 1;//(2,2)位置,2号选手与1号选手在第一天比赛 

		for(int j = 1; j <= m / 2; j++) {
			//同一水平线选手比赛
			k = b[i + j];
			r = b[i + m - j];
			plan[k][i + 1] = r;
			plan[r][i + 1] = k;
		}
	}
}
int main() {
	int n;//人数
	cout<<"请输入比赛人数"<<endl;
	cin>>n;
	lunzhuan(n);
	//打印表头
	cout<<"************"<<endl;
	cout<<"循环赛日程表"<<endl;
	cout<<"************"<<endl;
	cout<<"选手";
	for(int i=1; i<=n-1; i++)
		cout<<"\t"<<"第"<<i<<"天";
	cout<<endl;
	//
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			cout<<plan[i][j]<<"\t  ";
		}

		cout<<endl;
	}
	return 0;
}

二、最近点对问题

1、实验内容

利用分治算法、蛮力法,编程实现最近点对问题,并进行时间复杂性分析。注:要求针对计算机随机生成的100点对数据,分别用蛮力法和分治法求解最近点对,对比其复杂性。

2、实验分析

2.1题目分析
同时用蛮力法和分治法实现对最近点对问题的解决,比较解决问题的时间,复杂度等。
2.2蛮力法设计
直接使用双重for循环语句,来得出最近点对之间的距离。
2.3分治法设计
(1)先将所有点按x升序排列。
(2)划分x坐标中位数
(3)左递归求解左半部分点集最小d1
(4)右递归求解右半部分点集最小d2,d1和d2取最小值
(5)依次考察集合S中的点p(x,y),如果(x<=xm 并且x>=xm-d),则将点p放入集合P1中;如果(x>xm 并且x<=xm+d),则将点p放入集合P2中;
(6)将集合P1和P2按y坐标升序排列
(7)对集合P1和P2中的每个点p(x,y),在y坐标区间[y,y+d]内最对取出6个候选点,计算与点p的最近距离d3;返回min(d,d3)
2.4运行时间对比
使用clock()函数获取时间来。在函数运行前获取一次时间,在函数运行结束后获取一次时间,两次时间做差,估计认为运行时间。为了体现时间,中间采取一个循环来加大运行时间。
2.5时间复杂度分析
(1)蛮力法采取双重循环,时间复杂度为O(n^2);
(2)分治法。当k=2时,T(n)=1,当k>2时,T(n)=2T(n/2)+n
T(n)=0(nlog2n)
2.6生成随机点
采用rand()函数,生成0-500间的数

3、程序代码

/*最近点对问题*/
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<ctime>
using namespace std;

/*定义储存结构*/
struct node{
	int x;
	int y;
}; 

/*随机生成测试点*/
void creatpoint(node s[],int num)
{
	for(int i=0;i<num;i++)
	{
		s[i].x=rand()%500;
		s[i].y=rand()%500;
	 }
	 cout<<"生成成功"<<endl; 
	 for(int i=0;i<num;i++)
	 {
	 	cout<<"("<<s[i].x<<","<<s[i].y<<")  ";
	 }
 } 
 
  /*距离求解*/
 double distances(node a,node b)
 {
 	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
 }
 
 /*按坐标升序排列*/
bool cmpx(node &a,node &b)
 {
 	return a.x<b.x;
 }
 
/*按y坐标升序排列*/
bool cmpy(node &a,node &b)
 {
 	return a.y<b.y;
 }
 
 /*分治法求解*/
 double fenzhi(node s[],int low,int high)
 {

 	//cout<<"1"<<endl;
 	double d1,d2,d3,d;
 	int mid,i,j,index;
 	node p[101];//总点集
 	node minp1,minp2;
 	if(high-low==1)
 	{
 		return distances(s[low],s[high]);
	 }
 	if(high-low==2)
 	{
 		d1=distances(s[low],s[low+1]);
 		d2=distances(s[low+1],s[high]);
 		d3=distances(s[low],s[high]);
 		if((d1<d2)&&(d1<d3))
 		return d1;
 		else if(d2<d3) return d2;
		 else return d3; 
	 }
 	mid=(low+high)/2;//计算中间点
	d1=fenzhi(s,low,mid);//递归求解左
	d2=fenzhi(s,mid+1,high);//递归求解右
	if(d1<d2) d=d1;
	else d=d2;
	index=0;
	for(i=mid;(i>=low)&&(s[mid].x-s[i].x<d);i--)//建立p1 
	{
		p[index++]=s[i];
	 } 
	for(i=mid+1;(i<=high)&&(s[i].x-s[mid].x<d);i++)//建立p2 
	{
		p[index++]=s[i];
	}
	sort(p,p+index,cmpy);//对集合p1和p2按y坐标升序排列 
	for(i=0;i<index;i++)
	{
		for(j=i+1;j<index;j++)
		{
			if(p[j].y-p[i].y>=d)
			break;
			else{
				d3=distances(p[i],p[j]);
				if(d3<d)
				{
					d=d3;
					minp1=p[i];
					minp2=p[j];
				}	
			}
		}
		return d;
	 }
	 
 }
 
/*蛮力法解决*/
 void force(node p[],int length)
 {
		int i,j;
		double min,temp;
		
		node minp1=p[0];
		node minp2=p[1];

		min=distances(p[0],p[1]);
		for(i=0;i<length-1;i++)
		{
			for(j=i+1;j<length;j++)
			{
				temp=distances(p[i],p[j]);
				if(temp<min){
					min=temp;
					minp1=p[i];
					minp2=p[j];
				}
			}
		}
		cout<<endl;
		cout<<endl; 
		cout<<"最近点对为"<<endl;
		cout<<"("<<minp1.x<<")"<<"("<<minp1.y<<")和" <<"("<<minp2.x<<")"<<"("<<minp2.y<<")"<<endl;
		cout<<"******"<<endl;
	    cout<<"蛮力法"<<endl;
		cout<<"******"<<endl;
		cout<<"最近距离为: "<<min<<endl;
		cout<<endl;
  } 

 int main()
 {
 	node s[101];
 	creatpoint(s,100);
 	
 	//蛮力法解决
 	time_t b1,e1;
 	double t1;
 	b1=clock();
 	
	force(s,100);
	
	int m=10000000;
	while(m)
	{
		m--;
	}
	e1=clock();
	t1=double(e1-b1);
	
	cout<<"运行时间 "<<t1<<"ms"<<endl; 
	//分治法 
	time_t b2,e2;
	double t2;
	b2=clock();
	cout<<"******"<<endl;
	cout<<"分治法"<<endl; 
	cout<<"******"<<endl;
 	double n;
 	sort(s,s+100,cmpx);//按x升序将点集排列 
	n=fenzhi(s,0,100);
	cout<<"最近距离为 "<<endl; 
	cout<<n<<endl;
	int k=10000000;
	while(k)
	{
		k--;
	}
	e2=clock();
	t2=double(e2-b2);
	cout<<"运行时间 "<<t2<<"ms"<<endl;
 	return 0;
 }

实验二:动态规划法
实验三:贪心算法
实验四:回溯法

程序是蓝色的诗

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
递归分治算法是计算机科学中常用的算法设计方法,它们通常用于解决复杂的问题。在算法设计实验中,我们可以通过分析递归分治算法的性能以及实现过程来更深入地理解它们的原理和应用。 下面是针对递归分治算法设计实验分析: 1. 算法实现:在实验中,我们需要实现递归分治算法递归算法通常包含一个基本情况和一个递归情况。基本情况是结束递归的条件,而递归情况是通过调用自己来解决问题。分治算法通常包含三个步骤:分解问题、解决问题和合并结果。在分解问题的过程中,将原问题划分为若干个子问题,然后递归地解决子问题。在解决问题的过程中,对每个子问题进行求解。在合并结果的过程中,将子问题的结果合并成原问题的解。 2. 算法性能:在分析算法性能时,我们需要考虑算法时间复杂度和空间复杂度。递归算法时间复杂度通常与递归深度有关,而分治算法时间复杂度通常与问题规模有关。空间复杂度通常与算法递归深度和使用的数据结构有关。在实验中,我们可以通过比较递归分治算法时间复杂度和空间复杂度来评估它们的性能。 3. 算法应用:递归分治算法在实际应用中都有广泛的应用。递归算法适用于具有递归结构的问题,例如树和图。分治算法适用于可以分解为若干个子问题的问题,例如排序、查找和计算几何等问题。在实验中,我们可以通过应用递归分治算法来解决不同类型的问题,例如二叉树的遍历、归并排序和最近点对问题等。 总之,递归分治算法是计算机科学中非常重要的算法设计方法。通过实验,我们可以更好地理解它们的原理和应用,并且能够更加深入地研究算法的性能和实现过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

出云coding

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

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

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

打赏作者

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

抵扣说明:

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

余额充值