练习题1——递归算法设计
练习题:
- 输入一个自然数(<90000), 分别用递归法和非递归法求其二机制表示.
递归:
源码:
#include <iostream>
using namespace std;
int dec2bin(int n);
int main()
{ int n;
cout<<"请输入一个整数:";
cin>>n;
cout<<n<<"对应的二进制形式为:";
cout<<dec2bin(n);
cout<<endl;
return 0;
}
int dec2bin(int n)
{
int sum;
if(n==1)
return 1;
else
{
if(n==0)
{
return 0;
}
sum=dec2bin(n/2)*10+n%2;
}
return sum;
}
结果:
非递归:
源码:
#include<bits/stdc++.h>
//#include<iostream>
using namespace std;
stack<int> sta;
int main(){
int n;
while(cin>>n){
while(!sta.empty()) sta.pop();
if(n<0){
cout<<"-";
n=-n;
}
if(n==0){
puts("0");
continue;
}
while(n){
if(n&1) sta.push(1);
else sta.push(0);
n>>=1;
}
while(!sta.empty()){
cout<<sta.top();
sta.pop();
}
puts("");
}
return 0;
}
结果:
- 分别用递归法和非递归法求Fibonacci数列的前1000位,并比较计算时间的差异.
递归法:
源码:
#include<stdio.h>
//递归法
int fibonacci(int n)
{
if(n<=0)
{
return 0;
}
if(n==1 || n==2)
{
return 1;
}
return fibonacci(n-1) + fibonacci(n-2);
}
int main(void)
{
int n = 0,total=0;;
int i = 1;
int ret = 0;
printf("输入要求的斐波拉契数列项数:");
scanf("%d", &n);
for(i=1;i<=n;i++)
{
ret = fibonacci(i);
total = total + ret;
// printf("%d\n",ret);
}
//printf("第%d项 = %d\n",n,ret);
printf("前%d项和 = %d\n",n,total);
return 0;
}
结果:
非递归法:
源码:
#include<stdio.h>
int main()
{
int n = 0,n_dis=0,total=0;
int ret = 0;
int bef1 = 1;
int bef2 = 0;
printf("输入要求的斐波拉契数列项数:");
scanf("%d", &n);
n_dis = n;
while(n>0)
{
n = n - 1;
bef2 = bef1;
bef1 = ret;
ret = bef1 + bef2;
total = total + ret;
}
printf("前%d项和 = %d\n",n_dis,total);
return 0;
}
结果:
- 用递归算法完成如下问题:有52张牌,使它们全部正面朝上,第一轮是从第2张开始,凡是2的倍数位置上的牌翻成正面朝下;第二轮从第3张牌开始,凡是3的倍数位置上的牌,正面朝上的翻成正面朝下,正面朝下的翻成正面朝上;第三轮从第4张牌开始,凡是4的倍数位置上的牌按上面相同规则翻转,以此类推,直到第一张要翻的牌超过52为止。统计最后有几张牌正面朝上,以及它们的位置号.
递归思想:
源码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
bool card[100];
void turn(int x)
{
if(x>52)return;
for(int i=x;i<=52;i+=x)
{
card[i]=!card[i];
}
turn(x+1);
}
int main()
{
memset(card,1,sizeof(card));
turn(2);
for(int i=1;i<=52;i++)
{
if(card[i])
cout<<i<<endl;
}
return 0;
}
结果:
- 一个射击运动员打靶,靶一共有10环,连开6枪打中45环的可能性有多少种? (每一枪最少是0环,最多是10环)
思想:
源码:
#include <iostream>
using namespace std;
int sum;
int store[10];
void output()
{
++sum;
}
void compute(int score,int num)
{
if(score<0||score>(num+1)*10)
return;
if(num==0)
{
store[num]=score;
output();
return;
}
for(int i=0;i<=10;++i)
{
store[num]=i;
compute(score-i,num-1);
}
}
int main()
{
compute(45,5);
cout<<"总数"<<sum<<endl;
return 0;
}
结果:
- 在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,输出所有摆法。
分析:
1.想把8个皇后放进去,肯定最终每行只有一个皇后,每列只有一个皇后。
2.设个二维数组chess [ i ] [ j ] 模拟棋盘,cas存放摆法。i j 是表示i行j列:
写一个用于递归的函数,思路如下
3.从上往下一行行的放皇后,放下一行时从最左边(第0列)放起,如果不能放就往右挪一格再试。注意判断右边有没有越界出棋盘。
4.写一个函数专门判断当前位置能不能放,只需要判断该位置的横、竖、两对角线,这四条线上有没有其他皇后即可。命名为check。
5.如果把最后一行放完了,那就统计上这个摆法,cas++。摆完最后一行不能继续判断下一行了。
6.放完一种情况,还要探究其他情况,可以把现在放好的皇后“拿走”,然后再试探 之前没试探过的棋盘格。
7.拿走皇后操作可以和不能放皇后的操作用同样的代码实现:
如果这个位置不能放,要把它置零,表示没有皇后。
如果这位置能放,那就放皇后(置1)。等一种情况讨论完,还得把它拿开,“拿开”也是置零的操作。
所以应该想办法排列上述代码,保证已经把摆出的情况记录下来,之后执行“拿开皇后”代码。
源码:
#include<stdio.h>
#define line 8
void queen(int i,int j);
int check(int i,int j);
int chess[line][line];
int cas=0;
int xx,yy;
int main(){
queen(0,0);
printf("%d\n",cas);
return 0;
}
void queen(int i,int j){
if(j>=line){
return ;
}
if(check(i,j)==1){
chess[i][j]=1;
if(i==line-1){
cas++;
}
else{
queen(i+1,0); }
}
chess[i][j]=0; queen(i,j+1);
}
int check(int i,int j){
int k;
for(k=0;k<line;k++){
if(chess[i][k]==1) return 0; }
for(k=0;k<line;k++){
if(chess[k][j]==1) return 0;
}
for(k=-line;k<=line;k++){
if(i+k>=0&&i+k<line&&j+k>=0&&j+k<line) if(chess[i+k][j+k]==1) return 0;
if(i-k>=0&&i-k<line&&j+k>=0&&j+k<line) if(chess[i-k][j+k]==1) return 0;
}
return 1;
}
结果: