算法设计与分析期末考试复习(二)

分治法

将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。最好使子问题的规模大致相同。

  1. 分解(Divide):将一个难以直接解决的大问题,分割成一些规模较小的子问题,这些子问题互相独立,且与原问题相同。
  2. 递归求解子问题,若问题足够小则直接求解。
  3. 将各个子问题的解合并得到原问题的解。

求二叉树深度

int get_depth(BTPtr pbt){
	int dL,dR=0;
	if(pbt == NULL){
		return 0;
	}
	if((!ptb->lchild) && (!ptb->rchild)){
		return 1;
	}
	dL = get_depth(pbt->lchild);
	dR = get_depth(pbt->rchild);
	return 1 + ((dL>dR)?dL:dR);
}

分治法所能解决的问题一般具有四个特征:

  1. 该问题的规模缩小到一定的程序就可以容易地解决。
  2. 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
  3. 利用子问题的解可以合并得到原始问题的解。
  4. 各个子问题是相互独立的。

二分搜索技术,每执行一次算法while循环,待搜索数组的大小减少一半,因此最坏时间复杂度O(log n)

int BinarySearch(int a[],int x,int left,int right){
	while(left <= right){
		int mid = (left + right)/2;
		if(a[mid] == x){
			return mid;
		}else if(a[mid] < x){
			left = mid + 1;
		}else{
			right = mid - 1;
		}
	}
	return -1;
}

Master定理(递归复杂度判定定理)

在这里插入图片描述
大整数的乘法:将两个n位大整数相乘
传统逐位相乘、错位相加的传统方法:O(n2),效率太低。
分治法:将该问题分解为若干个规模较小的相同问题。
在这里插入图片描述
在这里插入图片描述
为了降低时间复杂度,必须减少乘法的次数。
在这里插入图片描述
在这里插入图片描述
两个XY复杂度都相同,但(a+b),(c+d)可能得到(n/2)+1位的结果,使问题的规模变大,故不选择第2种方案。

矩阵乘积的传统算法,时间复杂度O(n3)

void multi(int A[],int B[],int C[]){
	for(int i=1; i<=n ;i++){
		for(int j=1;j<=n;j++){
			C[i][j] = 0;
			for(int k=1 ;k<=n; k++){
				C[i][j] += A[i][k]*B[k][j];
			}
		}
	}
}

分治法:矩阵乘法
在这里插入图片描述
在这里插入图片描述
为了降低时间复杂度,必须减少乘法的次数。
在这里插入图片描述
棋盘覆盖问题:在一个2kx2k个方格组成的棋盘中,要求用图(b)所示的4种L形态骨牌覆盖给定的特殊棋盘,覆盖给定特殊棋盘上除特殊方格以外的所有方格,任何2个L型骨牌不得重叠覆盖。
在这里插入图片描述
分治策略技巧:使每个子棋盘均包含一个特殊的方格,从而将原问题分解为规模较小的棋盘覆盖问题。
在这里插入图片描述
棋盘覆盖问题中数据结构的设计:

  1. 棋盘:用二维数组board[size][size]表示一个棋盘,其中size=2k。为了在递归处理的过程中使用同一个棋盘,将数组board设为全局变量。
  2. 子棋盘:在棋盘数组board[size][size]中,用子棋盘左上角的tr、tc和棋盘边长s表示。
  3. 特殊方格:用board[dr][dc]表示,dr和dc是该特殊方格在棋盘数组board中的下标。
  4. L型骨牌:一个2k×2k的棋盘中有一个特殊方格,所以,用到L型骨牌的个数为(4k-1)/3,将所有L型骨牌从1开始连续编号,用一个全局变量t表示。
void ChessBoard(int tr,int tc,int dr,int dc,int size){
	if(size == 1)	return; //棋盘只有一个方格,且是特殊方格。
	t++;//L型骨牌号,已经初始化为0。
	s = size/2;//划分棋盘
	if(dr<tr+s && dc<tc+s){ //特殊方格在棋盘左上角
		ChessBoard(tr,tc,dr,dc,s);
	}else{ //用t号L型骨牌覆盖右下角,再递归处理子棋盘
		board[tr+s-1][tc+s-1] = t;
		ChessBoard(tr,tc,tr+s-1,tc+s-1,s);
	}
	
	if(dr<tr+s && dc >= tc+s){
		ChessBoard(tr,tc+s,dr,dc,s);
	}else{
		board[tr+s-1][tc+s] = t;
		ChessBoard(tr,tc+s,tr+s-1,tc+s,s);
	}

	if(dr>=tr+s && dc<tc+s){
		ChessBoard(tr+s,tc,dr,dc,s);
	}else{
		board[tr+s][tc+s-1] = t;
		ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
	}

	if(dr >= tr+s && dc >= tc+s){
		ChessBoard(tr+s,tc+s,dr,dc,s);
	}else{
		board[tr+s][tc+s] = t;
		ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
	}
}
  1. 当k>0时,将2的k次幂乘以2的k次幂分隔成为4个2的k-1次幂乘以2的k-1次幂子棋盘。
  2. 特殊方格必位于4个较小棋盘之一中,其余3个子棋盘中午特殊方格。
  3. 为了将这3个特殊方格的子棋盘转化为特殊棋盘,可以用一个L型骨牌将这3个较小棋盘的汇合处覆盖,这3个子棋盘上被L型骨牌覆盖的方格就成为该棋盘上的特殊方格,从而将原问题转换成4个较小规模的棋盘覆盖问题。递归地使用这种分割,直至棋盘简化为1*1棋盘。

在这里插入图片描述

快速排序:在数组中确定一个记录作为划分元,将数组中关键字小于划分元的记录移动到划分元之前,将数组中大于划分元的记录移动到划分元之后。

int Partition(int *arr,int L,int R){
	int left = L;
	int right = R;
	int pivot = arr[left];
	while(left < right){
		while(left<right && arr[right]>=pivot)
			right--;
		if(left < right){
			arr[left] = arr[right];
		}
		while(left<right && arr[left]<=pivot)
			left;
		if(left<right){
			arr[right] = arr[left];
		}
		if(left == right){
			arr[left] = pivot;
			return left;
		}
	}
}

void QuickSort(int *arr,int L,int R){
	if(L < R){
		int position = Partition(arr,L,R);
		quickSort(arr,L,position-1);
		quickSort(arr,position+1,R)
	}
}

最好情况:T(n)=O(nlogn)(每次总是选到中间值作为划分元)
最坏情况:T(n)=O(n2)(每次总是选到最小或最大元素作为划分元)
算法性能与系列中关键字的排列顺序和划分元的选取有关

  1. 当初始序列按关键字有序(正序或逆序)时,快速排序蜕化为冒泡排序,此时算法性能最差,时间复杂度为O(n2)。
  2. 可以用“三者取中”法来选取划分元,设:数组首记录为r[s]、尾记录为r[t],取:r[s]、r[t]和r[(s+t)/2]三者的中间值为划分元。
  3. 也可采用随机选取划分元的方式

快速排序算法的性能取决于划分的对称性。通过修改算法partition,可以设计出采用随机选择策略的快速排序算法。在a[p:r]中随机选出一个元素作为划分基准,这样可以使划分基准的选择是随机的,从而可以期望划分是比较对称的。

int RandomizedPartition(int a[],int p,int r){
	int i = random(p,r);
	swap(a[i],a[p]);
	Partition(a,p,r)
}

线性时间选择:给定线性序集中n个元素和一个整数k,要求找出这n个元素中第k小的元素,问是否可以在O(n)时间内得到解决,可以采用分治法,模仿快排对输入数组进行递归划分,只对划分出的子数组之一进行递归处理,子数组的选择与划分元和k相关。

int RandSelect(int A[],int start,int end,int k){
	if(start == end){
		return A[start];
	}
	int i = RandomizedPartition(A,start,end);
	int n = i-start+1;//左子数组的个数
	if(k <= n){
		RandSelect(A,start,n,k);
	}else{
		RandSelect(A,i+1,end,k-n;)
	}
}

线性时间内找到合理划分基准的步骤(select函数)

  1. 将n个元素划分成n/5个组,每组5个元素,只有可能一个组不是5个元素。
  2. 用任意一种排序算法对每组中的元素排序。
  3. 取出每组中的中位数,共n/5个元素。
  4. 递归调用select函数,找出这n/5元素中的中位数。
  5. 如果n/5为偶数,就选择2个中位数中较大的一个,以这个选出的元素作为划分基准。

按递增序列,找出下面29个元素的第18个元素:
8,31,60,33,17,4,51,57,49,35,11,43,37,3,13,52,6,19,25,32,54,16,5,41,7,23,22,46,29.

  1. 把前面29个元素分为6组(ceil(29/5));(8,31,60,33,17),(4,51,57,49,35),(11,43,37,3,13),(52,6,19,25,32),(54,16,5,41,7),(23,22,46,29).
  2. 提取每一组中的中值元素,构成集合{33,49,13,25,16,29}
  3. 递归地使用该算法求得集合中的中值,得到m=29.
  4. 根据m=29,把29个元素划分为3个子数组P={8,17,4,11, 3,13,6,19, 25,16,5,7,23,22},Q={29},R={31,60,33,51,57,49,35,43,37,52,32,54,41,46}
  5. P中有14个元素,Q中有1个元素,所以18-15=3,对R递归地执行本算法。
  6. 将R划分成3组(ceil(14/5)):{31,60,33,51,57},{49,35,43,37,52},{32,54,41,46}
  7. 求取这3组元素的中值元素分别为{51,43,46},这个集合的中值是43.
  8. 根据43将R划分成3组{31, 33, 35,37,32, 41},{43},{60, 51,57, 49, 52,54, 46}
  9. 因为k=3,第一个子数组的元素个数大于k,所以放弃后面两个子数组,以k=3对第一个子数组递归调用本算法;
  10. 将这个子数组分为5个元素为一组: {31,33,35,37,32}、{41},取中值为33。
  11. 根据33,把第一个子数组划分成{31,32},{33},{35,37};
  12. 因为k=3,而第一、第二个子数组的元素个数为3,所以33即为所求取的第18个小元素。
int Select(int a[],int start,int end,int k){
	if(end-start<75){
		//用某个简单的算法对数组a[start:end]排序
		return a[start+k-1];
	}
	for(int i=0; i<=(end-start-4)/5; i++){
		//将a[start+5*i]与a[start+4+5*i]的第3小元素与a[start+i]交换位置
	}
	//找出中位数中的中位数
	int x = Select(a,start,start+(end-start-4)/5,(end-start-4)/10);
	int i = Partition(a,start,end,x); //划分元位置
	int n = i-start+1; //左数组长度
	if(k <= n)	return Select(a,start,i,k);
	else{
		return Select(a,i+1,end,k-n);
	}
}

在这里插入图片描述

最接近点对:给定平面上的n个点,找出其中的一对点,使得在n个点组成的所有点对中,该点对的距离最小。

直观解法:将每一个点与其他n-1个点的距离算出,找出最小距离,时间复杂度:T(n)=n(n-1)=O(n2)
分治法

  1. 分解:将n个点的集合分成大小近似相等的两个子集。
  2. 求解:递归求解两个子集内部的最接近点对。
  3. 合并:从子空间内部最接近点对,和两个子空间之间的最接近点对中,选择最接近点对。
    在这里插入图片描述

分治法

  1. 假设我们用x轴上某个点m将S划分为2个子集S1和S2,基于平衡子问题的思想,用S中各点坐标的中位数来作分割点。
  2. 递归地在S1和S2找出其最接近点对{p1,p2}和{q1,q2}。
  3. 设d=min{|p1-p2|,|q1-q2|},则S中的最接近点对可能是{p1,p2},或者是{q1,q2},或者是某个{p3,q3},其中p3∈S1且q3∈S2。
  4. 如果最接近点对是{p3,q3},即|p3-q3|<d:即p3和q3两者之间的基于不超过d,p3∈(m-d, m],q3∈(m, m+d]。
bool Cpair1(S,d){
	n = |S|;
	if(n < 2){
		d =;
		return false; 
	}
	m = S中各点坐标的中位数。
	构造S1和S2 //构造S1={x  S|x<=m}, S2={x  S|x>m}
	Cpair(S1,d1);
	Cpair1(S2,d2);
	p = max(S1);
	q = min(S2);
	d = min(d1,d2,q-p);
	return true;
}

考虑二维的情况
在这里插入图片描述

  1. 选取二维平面的一条垂直线L:x=m作为分割线,其中m为S中各点x坐标的中位数,由此将S分割成S1和S2。
  2. 递归地在S1和S2上找出其中最小距离d1,d2。
  3. 设d=min{d1,d2},S中的最接近点对间的距离或者是d,或者是某个点对{p,q}之间的距离,其中p∈S1且q∈S2。如果用符号P1和P2分别表示直线 L 的左右两边宽为d的区域,则必有p∈P1且q∈P2

在这里插入图片描述
考虑P1中任意一点p,它若与P2中的点q构成最接近点对的候选者,则必由distance(p,q)<d,P2中满足条件的点一定落在矩形R中,矩阵R的大小为dx2d。
由d的定义可知:P2中任何2个点(qi∈S)的距离都不小于d,由此可以推出矩形R中最多只有6个S中的点。
在分治法的合并步骤中最多只需要检查6×n/2=3n个候选者

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
计算机算法设计与分析 期末试题 一。选择题 1、分搜索算法是利用( A )实现的算法。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 2、下列不是动态规划算法基本步骤的是( A )。 A、找出最优解的性质 B、构造最优解 C、算出最优解 D、定义最优解 3、最大效益优先是( A )的一搜索方式。 A、分支界限法 B、动态规划法 C、贪心法 D、回溯法 4、在下列算法中有时找不到问题解的是( B )。 A、蒙特卡罗算法 B、拉斯维加斯算法 C、舍伍德算法 D、数值概率算法 5. 回溯法解旅行售货员问题时的解空间树是( A )。 A、子集树 B、排列树 C、深度优先生成树 D、广度优先生成树 6.下列算法中通常以自底向上的方式求解最优解的是( B )。 A、备忘录法 B、动态规划法 C、贪心法 D、回溯法 7、衡量一个算法好坏的标准是(C )。 A 运行速度快 B 占用空间少 C 时间复杂度低 D 代码短 8、以下不可以使用分治法求解的是(D )。 A 棋盘覆盖问题 B 选择问题 C 归并排序 D 0/1背包问题 9. 实现循环赛日程表利用的算法是( A )。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 10、下列随机算法中运行时有时候成功有时候失败的是(C ) A 数值概率算法 B 舍伍德算法 C 拉斯维加斯算法 D 蒙特卡罗算法 11.下面不是分支界限法搜索方式的是( D )。 A、广度优先 B、最小耗费优先 C、最大效益优先 D、深度优先 12.下列算法中通常以深度优先方式系统搜索问题解的是( D )。 A、备忘录法 B、动态规划法 C、贪心法 D、回溯法 13.备忘录方法是那种算法的变形。( B ) A、分治法 B、动态规划法 C、贪心法 D、回溯法 14.哈弗曼编码的贪心算法所需的计算时间为( B )。 A、O(n2n) B、O(nlogn) C、O(2n) D、O(n) 15.分支限界法解最大团问题时,活结点表的组织形式是( B )。 A、最小堆 B、最大堆 C、栈 D、数组 16.最长公共子序列算法利用的算法是( B )。 A、分支界限法 B、动态规划法 C、贪心法 D、回溯法 17.实现棋盘覆盖算法利用的算法是( A )。 A、分治法 B、动态规划法 C、贪心法 D、回溯法 18.下面是贪心算法的基本要素的是( C )。 A、重叠子问题 B、构造最优解 C、贪心选择性质 D、定义最优解 19.回溯法的效率不依赖于下列哪些因素( D ) A.满足显约束的值的个数 B. 计算约束函数的时间 C. 计算限界函数的时间 D. 确定解空间的时间 20.下面哪种函数是回溯法中为避免无效搜索采取的策略( B ) A.递归函数 B.剪枝函数 C。随机数函数 D.搜索函数 21、下面关于NP问题说法正确的是(B ) A NP问题都是不可能解决的问题 B P类问题包含在NP类问题中 C NP完全问题是P类问题的子集 D NP类问题包含在P类问题中 22、蒙特卡罗算法是( B )的一种。 A、分支界限算法 B、概率算法 C、贪心算法 D、回溯算法 23.下列哪一种算法不是随机化算法( C ) A. 蒙特卡罗算法B. 拉斯维加斯算法C.动态规划算法D.舍伍德算法 24. ( D )是贪心算法与动态规划算法的共同点。 A、重叠子问题 B、构造最优解 C、贪心选择性质 D、最优子结构性质 25. 矩阵连乘问题的算法可由( B)设计实现。 A、分支界限算法 B、动态规划算法 C、贪心算法 D、回溯算法 26. 分支限界法解旅行售货员问题时,活结点表的组织形式是( A )。 A、最小堆 B、最大堆 C、栈 D、数组 27、Strassen矩阵乘法是利用( A )实现的算法。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 29、使用分治法求解不需要满足的条件是(A )。 A 子问题必须是一样的 B 子问题不能够重复 C 子问题的解可以合并 D 原问题和子问题使用相同的方法解 30、下面问题(B )不能使用贪心法解决。 A 单源最短路径问题 B N皇后问题 C 最小花费生成树问题 D 背包问题 31、下列算法中不能解决0/1背包问题的是(A ) A 贪心法 B 动态规划 C 回溯法 D 分支限界法 32、回溯法搜索状态空间树是按照(C )的顺序。 A 中序遍历 B 广度优先遍历 C 深度优先遍历 D 层次优先遍历 33、下列随机算法中运行时有时候成功有时候失败的是(C ) A 数值概率算法 B 舍伍德算法 C 拉斯维加斯算法 D 蒙特卡罗算法 34.实现合并排序利用的算法是( A )。 A、分治策略 B、动态规划法 C、贪心法 D、回溯法 35.下列是动态规划算法基本要素的是( D )。 A、定义最优解 B、构造最优解 C

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

饼干饼干圆又圆

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

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

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

打赏作者

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

抵扣说明:

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

余额充值