算法--分治与递归1

《算法设计与分析》实验报告
 
 
实验名称     :       实验1 递归与分治 1                   
            
人工智能与信息技术学院
南京中医药大学

实验目的:
(1) 熟悉递归与分治的概念
(2) 掌握递归与分治的使用
实验内容和要求
任务一:用递归方法解决以下问题。
X星球特别讲究秩序,所有道路都是单行线。一个甲壳虫车队,共16辆车,按照编号先后发车,夹在其它车流中,缓缓前行。
路边有个死胡同,只能容一辆车通过,是临时的检查站,如图所示。

X星球太死板,要求每辆路过的车必须进入检查站,也可能不检查就放行,也可能仔细检查。
如果车辆进入检查站和离开的次序可以任意交错。那么,该车队再次上路后,可能的次序有多少种?
为了方便起见,假设检查站可容纳任意数量的汽车。
显然,如果车队只有1辆车,可能次序1种;2辆车可能次序2种;3辆车可能次序5种。
现在足足有16辆车啊,亲!需要你计算出可能次序的数目。
这是一个整数,请输出答案,不要输出任何多余的内容(比如说明性文字)。
输入
没有输入。
输出
输出一个整数,即可能次序的数目。

 
任务二:实现数据结构中的快速排序,并用快排解决以下问题:
 
在一个划分成网格的操场上,n个士兵散乱地站在网格上,网格点由整数坐标(x,y)表示,士兵们可以沿网格边上、下、左、右移动,移动一格算一步。按照军官的命令,士兵们要整齐的列成一格水平队列,即排成(x,y),(x+1,y),....(x+n-1,y)。
问题是:如何选择x和y的值使得士兵们以最少的移动步数排成一列。
样例输入输出:
请输入士兵数目:
5
请输入5个士兵的坐标位置:
1 2
2 2
1 3
3 -2
3 3
使士兵排成一行所要移动的最少步数为:
8
思路:往中间靠拢才会总移动步数最少!将X轴和Y轴分开来看
1、对于Y方向
设n个士兵的排序之后的Y轴坐标分别为:Y1,Y2 …… …… Yn, 他们最后站在同一行上,设目标坐标为Y0,
则n个士兵最终在Y轴的需要移动的总的步数值为S1:
S1=|Y1-Y0|+|Y2-Y0|+ …… …… +|Yn-Y0|
结论:Y0取所有Yi的中间值时可以使得S1达到最小(这个结论可以证明)
2、对于X方向
(1)首先需要对所有士兵的X轴坐标值进行排序(为了方便就近移动)
(2)然后,按从左至右的顺序依次求出每个士兵所对应的“最终位置”(最优),所移动的步数总和就是X轴方向上需要移动的步数
设排序后n个士兵在X轴坐标为: X1,X2 ,X3 …… …… Xn
他们最终位置”的X轴坐标值为:X0,X0+1,X0+2 …… …… X0+(n-1)
则n个士兵最终X轴的需要移动的总的步数值为S2:S2=|X1-X0| + |X2-(X0+1)|++|Xn-(X0+n-1)|
经过变换S2=|X1-X0|+ |(X2-1)-X0|++|(Xn-(n-1))-X0|
注意到公式的形式与Y轴方向上的考虑一样,同样是n个已知数分别减去一个待定数后取绝对值,然后求和
结论:求出x1, x2-1,… Xn-(n-1) 的中位数,即求得X0值,最后算出最优解。
思考:
1、如果n为偶数,中位数如何求?中间两个加起来除2
2、找中位数是否需要对整个数组排序?是否可以改进算法?
为了方便就近移动
任务三:给定 a, 分治法设计出求 a^n 的算法

	

 
 
 
 
算法设计思想
 任务一:递归,栈,在检查地方有车分为进站和出站两种没有车只有入站直到所有车全部进站
任务二:注意到公式的形式与Y轴方向上的考虑一样,同样是n个已知数分别减去一个待定数后取绝对值,然后求和
结论:求出x1, x2-1,… Xn-(n-1) 的中位数,即求得X0值,最后算出最优解。
任务三:分治,分成偶数和奇数然后使用递归
程序设计(给出代码,加上必要的注释)
 #include <iostream>
using namespace  std;
//根据公式h(n)=h(0)*h(n-1)+h(1)*h(n-2)+.....+h(n-1)*h(0)  (n>=2,h(0)=h(1)=1)
//C(2n,n)/(n+1)  
int Car(int n, int m)//n为没有入栈的车的数量,m为没有出栈的数量
{
	if (n == 0) //如果所有车都已经入栈,那么只有一种出去的结果
		return 1;
    if (m == 0) //如果检车站车全部出去了
		return Car(n - 1, 1);
    if (m > 0)//如果检车站有车还没出去
		//分两种情况,车辆入站和出站
		return Car(n - 1, m + 1) + Car(n, m - 1);
	return 0;
}

int main()
{
	cout<<Car(16,0);
	return 0;
}
//士兵移动到一排
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxa = 10000;
struct node
{
 int x, y;
}e[maxa];//士兵的坐标
int n;
double  num= 0;
int cmpy(node a, node b)
{
    return a.y < b.y;
}

int cmpx(node a, node b)
{
    return a.x < b.x;
}

int main()
{
    cout << "请输入士兵的人数:" << endl;
    cin >> n;
    cout << "请输入士兵的坐标(x,y),仅输入x和y的值即可" << endl;
    for (int i = 1; i <= n; i++)
    {
       cin>> e[i].x>>e[i].y;
    }
    sort(e + 1, e + n + 1, cmpy);
    int midy = e[(1 + n) / 2].y;//求y的中位数
    for (int i = 1; i <= n; i++)//计算y轴移动的步数
    {
        num += abs(e[i].y - midy);
    }
    sort(e + 1, e + n + 1, cmpx);//排序
    for (int i = 1; i <= n; i++)
    {
        e[i].x = e[i].x - i;
    }
    sort(e + 1, e + n + 1, cmpx);
    int midx = e[(1 + n) / 2].x;//求x的中位数
    for (int i = 1; i <= n; i++)
    {
        num += abs(e[i].x - midx);
    }
    cout <<"士兵移动的步数为"<< num << endl;
    return 0;
}

// 用分治法求a^n。
#include<iostream>
using namespace std;

double f(int a, int n) //求a^n函数
{
	if (n == 1)
		return a;
	else
	{
		if (n % 2 == 0)//如果n为偶数
			return f(a, n / 2) * f(a, n / 2);
		else  return f(a, n / 2) * f(a, n / 2 + 1);//如果n为奇数
	}
}
int main()
{
	int a, n;
	cout << "请输入 a和n: ";
	cin >> a >> n;
	cout << a << "的" << n << "次方为:" << f(a, n)<< endl;
	system("pause");
	return 0;
}

运行结果(写清题号)
 任务一

任务二

任务三


算法分析
 递归: 递归是指一个函数自己调用自己。利用数学表达式可表达为:f(x)= f(x-1+1递归算法一般要经历两个过程: 递推(归)和回溯
1、基准情形:必须要有某个基准情形,它无需递归就能解出2、不断推进:对于需要求解的情形,每次递归调用都必须要使状况朝向一种基本情况推进。3、设计法则:假设所有的递归调用都能运行。4、合成效益发展:在求解一个问题的同一实例时,切勿在不同的递归调用中做重复性的工作(例如使用递归计算斐波那契数列)
分治算法,就是把一个大的问题分为很多个形式相同的子问题,把问题规模缩小。假使,最初的问题规模是N,这些小的子问题的个数为a,子问题的规模是n / b,分解或者合并的复杂度表示为f( n ),那么总的时间复杂度就可以表示为

实验心得与小结
 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
五大常用算法是动态规划、分治递归、贪心和回溯。 动态规划是一种将问题分解成子问题并保存子问题解的方法。通过求解子问题,可以逐步推导出原始问题的解。动态规划通常用于求解最优化问题,例如最长公共子序列、最短路径等。 分治是将原问题划分成多个相互独立的子问题,然后通过递归的方式求解子问题,并将子问题的解合并成原问题的解。分治算法常用于排序、快速幂等问题。 递归是通过函数调用自身来解决问题的方法。递归算法在问题定义可以被分解为较小规模或更简单情况的时候很有用。例如,计算一个数的阶乘,就可以使用递归实现。 贪心算法是一种选择当前最优策略的方法,即在每一步选取最优解,最终得到全局最优解的算法。贪心算法通常用于解决无后效性的问题,例如最小生成树、哈夫曼编码等。 回溯是一种通过穷举搜索所有可能的解空间,找到满足条件的解的方法。回溯算法在解决组合问题、排序问题、子集和问题等方面很有效。回溯算法通过递归的方式逐步构建解,当发现当前解不满足条件时,会回退到上一步继续搜索其他可能的解。 这五种常用算法在不同的问题领域中都有广泛应用,每种算法都有自己的特点和适用范围。在解决具体问题时,可以根据问题的性质和要求选择最适合的算法进行求解。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值