算法设计与分析—递归与分治(持续更新中…虽然也没什么人看吧,hhh)
分治概念:将一个大规模问题分解为若干个小规模问题,以便逐个击破,即分而治之!
递归概念:直接或间接调用自身的算法成为递归。
二者的相关性十分强,这也是为什么教材把这两个算法归在一章里的原因。
问题一,输出全排列(不按照大小输出,要求使用递归不使用回溯)
input:
输入一个正整数(不要太大,递归层数稍微一多就超时!!!)
output:
输出1----n的全排列
input_case:
3
output_case:
123
132
213
231
321
312
思路:
递归一定要找好递归边界与递归关系!!!
设置函数P(int *a,int k,int n);
k从0开始计数,k到达问题边界就输出一下;
k没到边界开始,分别以每一个元素作为前缀进行递归输出!
code:
//输出全排列(递归实现)---非顺序输出
#include<stdio.h>
using namespace std;
template<class T>
inline void swap(T &t1,T &t2){
T temp=t1;
t1=t2;
t2=temp;
return ;
}
void P(int *a,int k,int n)
{
if(k==n){
for(int i=0;i<n;i++){
printf("%d",a[i]);
}
printf("\n");
return ;
}else{
for(int i=k;i<n;i++){
swap(a[k],a[i]);
P(a,k+1,n);
swap(a[k],a[i]);
}
}
return ;
}
int main(){
int n;
scanf("%d",&n);
int a[n];
for(int i=1;i<=n;i++){
a[i-1]=i;
}
P(a,0,n);
return 0;
}
问题二,汉诺塔问题
问题描述:
有a,b,c三个塔,a上有n个盘子,从小到大依次罗列,将这n个盘子从a移到c上,
注意:大盘不能压小盘;
一次只能移一盘;
input:
输入一个正整数,代表问题规模,不要太大!
output:
输出问题的移动过程:(以这种方式输出即可)
%c->%c\n
最后输出一共移动了多少次:(正整数)
Input_case:
3
output_case:
A->C
A->B
C->B
A->C
B->A
B->C
A->C
cnt=7
思路:
对于大规模问题无法直接求解,将其分为小规模问题(分治思想)!
code:
#include<stdio.h>
void hanoi(int n,char x,char y,char z);
int cnt=0;
int main(){
int n;
scanf("%d",&n);
hanoi(n,'A','B','C');
printf("cnt=%d",cnt);
return 0;
}
void hanoi(int n,char x,char y,char z){
if(n==1){
//递归边界
printf("%c->%c\n",x,z);cnt++;
}else{
//如果不是边界就一直递归调用
hanoi(n-1,x,z,y);//将x借助z移到y
printf("%c->%c\n",x,z);//输出路径
cnt++;
hanoi(n-1,y,x,z);//将x借助y移到z
}
}
问题三,二分查找
问题描述:
对于已经从小到大排好序的数组a[0…n-1];
找出其中值为x的下标;
如果没有找到输出NULL;
input:
输入正整数n;
接下来输入n个正整数(从小到大);
在输入所要查找的值x;
output:
输出x对应在数组的下标;
如果没有x输出NULL;
input_case:
5
1 3 4 6 8
6
output_case:
3
code:
#include<stdio.h>
int search(int *a,int low,int high,int x){
int mid=(low+high)/2;
if(low==high&&a[mid]!=x)return -1;//没有找到
if(a[mid]==x){
//找到了输出mid
return mid;
}else if(a[mid]>x){
//从左侧找
return search(a,low,mid,x);
}else{
//从右侧找
return search(a,mid+1,high,x);
}
}
int main(){
int n;
scanf("%d",&n);
int a[n];
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
int x;
scanf("%d",&x);
int ans=search(a,0,n-1,x);
if(ans>=0){
printf("%d",ans);
}else{
printf("NULL");
}
return 0;
}
时间复杂度:O(logn);
问题四,大整数相乘问题(分析)
问题描述:
两个非常大的正整数(以二进制形式给出)如何降低时间复杂度?
分析:
时间复杂度:从O(n^2)------>O(n ^1.59)
问题五,Strassen矩阵乘法(分析)
问题描述:
对于nXn的方阵A乘以nXn的方针B形成nXn的方针C;
需要O(n^3)的时间复杂度
如何降阶呢?
分析:
将nXn的矩阵分成4个(n/2)X(n/2)的矩阵,这样时间复杂度为:
时间复杂度:O(n^3)-------->O(n ^2.81)