您的位置:首页 > 其它

期末复习——递归与分治策略

2017-12-31 10:18 344 查看
【1】阶乘函数

int DiGui(int n)
{
if(n==0)
return 1;
return n*DiGui(n-1);
}


【2】Fibonacci数列

无穷数列1,1,2,3,5,8,13,21,34,55,…,称为Fibonacci数列。当n=0时,F(n)=1; 当n=1时,F(n)=1; 当n>1时,F(n)=F(n-1)+F(n+2).

int ShuLie(int n)
{
if(n<=1)
return 1;
return fibonacci(n-1)+fibonacci(n-2);
}


【3】排列问题

设R={r1,r2,r3,r4,………,rn}是要进行排列的n个元素,Ri=R-{ri}。集合X中元素的全排列记为Perm(X). (ri)Perm(X)的每一个排列前加上前缀ri得到的排列。R的全排列可归纳为:

当n=1时,Perm(R)=(r),其中r是集合R中唯一的元素;

当n>1时,Perm(R) 由 (r1)Perm(R1) 、 (r2)Perm(R2) 、(r3)Perm(R3) ,。。。(rn)Perm(Rn) 构成

Problem A: 分治法求解全排列问题
Description
设R=(1, 2, .., n),计算R的全排列。 分治法求解全排列的算法思想: 设R=(1, 2, .., n)的全排列为P(R), 若R=(),则P()=(); 否则,P(R)={(1)P(2, 3, .., n),(2)P(1, 3, .., n), (3)P(2, 1, .., n), .., (n)P(2, .., n-1, 1)}; 同样地,P(2, 3, .., n)={(2){3, 4, .., n}, (3){2, 4, .., n}, .., (n){3, .., n-1, 2}}
Input
输入为一组不大于7的整数。
Output
对每个输入的整数n,用分治法计算并输出1..n的全排列。
Sample Input
1
2
3
Sample Output
1
1 2
2 1
1 2 3
1 3 2
2 1 3
2 3 1
3 2 1
3 1 2

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<malloc.h>
using namespace std;
void perm(int a[],int k,int m){
int i;
if(k==m){
for(i=0;i<=m;i++)
printf("%d ",a[i]);
printf("\n");
return;
}
else{
for(i=k;i<=m;i++){
swap(a[i],a[k]);
perm(a,k+1,m);
swap(a[i],a[k]);
}
}
}
int main(){
int n;
int a[100];
while(~scanf("%d",&n)){
int i;
for(i=0;i<n;i++){
a[i]=i+1;
}
perm(a,0,n-1);
}
return 0;
}


【4】整数划分问题

将整数n表示成一系列正整数之和,n=n1+n2+n3+……+nk (其中,n1>>n2>>n3>>………..>>nk>>1,k>>1)

将正整数n表示成一系列正整数之和:n=n1+n2+…+nk, 其中n1>=n2>=….>=nk>=1, k >=1

求正整数n的不同划分个数。

例如正整数6有如下11中不同的划分:

6

5+1

4+2,4+1+1

3+3,3+2+1,3+1+1+1

2+2+2,2+2+1+1,2+1+1+1+1

1+1+1+1+1+1

int q(int n,int m)
{
if((n<1)||(m<1))
return 0;
if((n==1)||(m==1))
return 1;
if(n<m)
return q(n,n);
if(n==m)
return q(n,m-1)+1;
return q(n,m-1)+q(n-m,m);
}


问题描述
  一个正整数可以划分为多个正整数的和,比如n=3时:
  3;1+2;1+1+1;
  共有三种划分方法。
  给出一个正整数,问有多少种划分方法。
输入格式
  一个正整数n
输出格式
  一个正整数,表示划分方案数
样例输入
3
样例输出
3

#include<iostream>
using namespace std;

int fun(int n, int m)
{
if(n == 1 || m == 1)
return 1;
else if(n < m)
return fun(n, n);
else if(n == m)
return fun(n, m-1) + 1;
else
return fun(n, m-1) + fun(n-m, m);
}

int main()
{
int n;
cin>>n;
cout<<fun(n, n)<<endl;

return 0;
}


【5】汉诺塔问题

void hanoi(int n,int a,int b,int c)
{
if(n>0)
{
hanoi(n-1,a,c,b);
move(a,b);
hanoi(n-1,c,b,a);
}
}


Description
假设有三个分别命名为X、Y和Z的塔座,在塔座X上插有n个直径大小各不相同、依小到大编号为1,2,...,n的圆盘。现要求将X轴上的n个圆盘移至塔座Z上并仍按同样顺序叠排,圆盘移动时必须遵循下列规则: 1)每次只能移动一个圆盘; 2)圆盘可以插在X、Y和Z中的任一塔座上; 3)任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。 如何实现移动圆盘的操作呢?当n=1时,问题比较简单,只要将编号为1的圆盘从塔座X直接移至塔座Z上即可;当n>1时,需利用塔座Y作辅助塔座,若能设法将压在编号为n的圆盘之上的n-1个圆盘从塔座X(依照上述法则)移至塔座Y上,则可先将编号为n的圆盘从塔座X移至塔座Z上,然后再将塔座Y上的n-1个圆盘(依照上述法则)移至塔座Z上。而如何将n-1个圆盘从一个塔座移至另一个塔座的问题是一个和原问题具有相同特征属性的问题,只是问题的规模小1,因此可以用同样的方法求解。由此可得如下图算法所示的求解n阶Hanoi塔问题的C函数。
Input
输入数据有多组,每组1个整数n,表示Hanoi塔的阶数。
Output
将每次移动(move)按照以下格式输出:%2d. Move disk %d from %c to %c\n
上述格式中第一个整数表示第几次移动,第二个整数表示移动第几个圆盘,后两个字符表示将圆盘从哪个塔座移至哪个塔座上。每组输出后面输出一个空行。
Sample Input
1
2
3
Sample Output
1. Move disk 1 from X to Z
1. Move disk 1 from X to Y
2. Move disk 2 from X to Z
3. Move disk 1 from Y to Z

1. Move disk 1 from X to Z
2. Move disk 2 from X to Y
3. Move disk 1 from Z to Y
4. Move disk 3 from X to Z
5. Move disk 1 from Y to X
6. Move disk 2 from Y to Z
7. Move disk 1 from X to Z

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<malloc.h>
#include<math.h>
int i=1;
void move(int n,char from,char to){
printf("%2d. Move disk %d from %c to %c\n",i++,n,from,to);
}
void hanoi(int n,char from,char dep,char to){
if(n==1){
move(1,from,to);
}
else{
hanoi(n-1,from,to,dep);
move(n,from,to);
hanoi(n-1,dep,from,to);
}
}
int main(){
int n;
while(scanf("%d",&n)==1){
char a='X',b='Y',c='Z';
hanoi(n,a,b,c);
printf("\n");
i=1;
}
return 0;
}


【6】大整数乘法

Description

大整数是指远远超过C/C++语言的整数类型表示范围的整数,你的任务是计算两个大整数的乘积。

Input

输入包括两行,每行一个大整数n(n小于10的100次方)

Output

输出包括一行,即为大整数的乘积

Sample Input

11111111111111111111111111111

11111111111111111111111111111

Sample Output

123456790123456790123456790120987654320987654320987654321

#include<stdio.h>
#include<string.h>
int multiplication()
{
int num1[100]={0},num2[100]={0},mult[201]={0},mult2[201]={0};
int i,j,len1,len2,k1,k2,t,m;
char ch1[100],ch2[100];
gets(ch1);
len1=strlen(ch1);
for(k1=0;k1<len1;k1++)
num1[k1]=ch1[len1-k1-1]-'0';
gets(ch2);
len2=strlen(ch2);
for(k2=0;k2<len2;k2++)
num2[k2]=ch2[len2-k2-1]-'0';
for(i=0;i<len1;i++)
{
for(j=0;j<len2;j++)
{
m=num1[i]*num2[j]+mult[i+j];
mult[i+j]=(num1[i]*num2[j]+mult[i+j])%10;
t=m/10;
mult[i+j+1]+=t;
}

}
for(i=0;i<len1+len2;i++)
{
mult2[i]=mult[len1+len2-i-1];
}
i=0;
while(1)
{
if(mult2[i]!=0)
break;
else
{
i++;
}
}
for(j=i;j<len1+len2;j++)
{
printf("%d",mult2[j]);
}

}
int main()
{
multiplication();
}


【7】循环赛日程表

设有n=2^k个运动员进行网球比赛,现在要设计一个足以满足以下要求的比赛日程表:

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

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

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

按照此要求,可以将比赛日程表设计成有n行和n-1列的表,在表中第i行和第j列填入第i个选手第j天所遇到的对手。

#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;

void Table(int k,int n,int **a);
void input(int &k);
void output(int **a,int n);

int main()
{
int k;
input(k);

int n=1;
//n=2^k(k>=1)个选手参加比赛
for(int i=1; i<=k; i++)
n *= 2;

//根据n动态分配二维数组a
int **a = new int *[n+1];
for(int i=0;i<=n;i++)
{
a[i] = new int[n+1];//数组的每一行
}

Table(k,n,a);

cout<<"循环赛事日程表为:"<<endl;
output(a,n);

//释放空间
for(int i=0;i<=n;i++)
{
delete[] a[i];
}
delete[] a;

return 0;
}

void input(int &k)
{
cout<<"请输入k值:"<<endl;
cin>>k;
}

void output(int **a,int n)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}

void Table(int k,int n,int **a)
{//n=2^k个选手
for(int i=1; i<=n; i++)
a[1][i]=i;//设置日程表第一行

int m = 1;//每次填充时,起始填充位置
for(int s=1; s<=k; s++)
{
n /= 2;
for(int t=1; t<=n; t++)
{
for(int i=m+1; i<=2*m; i++)//控制行,填充第i行
{
for(int j=m+1; j<=2*m; j++)//控制列
{
a[i][j+(t-1)*m*2] = a[i-m][j+(t-1)*m*2-m];//右下角等于左上角的值
a[i][j+(t-1)*m*2-m] = a[i-m][j+(t-1)*m*2];//左下角等于右上角的值
}

}
}
m *= 2;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: