1. 程式人生 > >遞迴思想以及例項練習

遞迴思想以及例項練習

思想分析:

     1.對問題的細化成小問題。

     2.自己呼叫比自己小一個規模的自己。

     3.有結束條件。

滿足條件:

     1.有遞迴公式。問題能夠分解為一個一個於自身類似的小問題。

     2.有確切的邊界。能夠最後分解為一個有確定解的問題。

一、一個人趕著鴨子去每個村莊賣,每經過一個村子賣去所趕鴨子的一半又一隻。這樣他經過了七個村子後還剩兩隻鴨子,問他出發時共趕多少隻鴨子?經過每個村子賣出多少隻鴨子

分析:經過7個村莊後還剩兩隻雞鴨子,每經過一個村莊賣當前鴨子的一半加一隻,所以遞迴體是經過前一個村子的鴨子數除以2再減去1就是到達下一個村子的時候的鴨子數,所以要想求在第一個村子的鴨子數,必須從後往前推。

演算法: 當i=0時,結束遞迴呼叫,當i>0時,故有:

            If(i=0)

                 Cout<< “共有x只鴨子”;

            Else

                  Returnf(x+1);

程式碼實現:

#include <stdio.h>
#include "iostream"
using namespace std;
 
int number = 2,x,i=7;
 
int Number(int i) 
{
     	if(0 == i)           //當i為0時,結束遞迴呼叫 
	    {
		    cout << "他出發時共趕了" << number << "只鴨子。" << endl;  //當經過的村子數為0時,number為出發時的鴨子數 
	    }
	     else
     	{ 
	     	number = (number + 1 ) * 2;   //計算在經過第i個村子前的鴨子數number
           	x = number / 2 + 1;           //計算在經過第i 個村子時賣的鴨子數x 
	     	cout << "經過第" << i << "個村子時,他賣出" << x << "只鴨子。" << endl;
		    return Number(i - 1);
	    } 
}
int main()
{
	Number(7);	
}

二、角谷定理。輸入一個自然數,若為偶數,則把它除以2,若為奇數,則把它乘以3加1。經過如此有限次運算後,總可以得到自然數值1。求經過多少次可得到自然數1。

如:輸入22,

輸出 2211 34 17 52 26 13 40 20 10 5 16 8 4 2 1

 STEP=16

分析:設fun(n)表示關於自然數n的一個函式,由題意已知,當n=1時,fun(1)=1。

           當n>1且n為偶數時,fun(n)=fun(n/2);

           當 n>1且n為奇數時,fun(n)=fun(3*n+1)。

          最後得到自然數1的運算次數為每次運算次數之和。

演算法:fun(n)=1          n=1

           fun(n)=fun(n/2)    n>1且n為偶數

           fun(n)=fun(3*n+1)  n>1且n為奇數

程式碼實現:

#include<iostream>
using namespace std;

int Angle(int n,int i)
{
	if(n==1)  //當n 為1時,退出遞迴
	{
		cout<<endl<<"STEP="<<i<<endl; //輸出次數
		return 1;
	}
	else
	{
		if(n%2==0) //當n為偶數時
		{
			cout<<n/2<<" ";
			i=i+1;  //次數加1
			return Angle(n/2,i);
		}
		else  //當n為奇數時
		{
			cout<<3*n+1<<" ";
			i=i+1;
			return Angle(3*n+1,i);
		}
		cout<<endl<<"STEP="<<i<<endl; //輸出次數
	}
}

void main()
{
	int m,j=1;//m為自然數,j為執行次數
	scanf("%d",&m);
	Angle(m,j);
	system("pause");
	return;
}

三、電話號碼對應的字元組合:在電話或者手機上,一個數字如2對應著字母ABC,7對應著PQRS。那麼數字串27所對應的字元的可能組合就有3*4=12種(如AP,BR等)。現在輸入一個3到11位長的電話號碼,請打印出這個電話號碼所對應的字元的所有可能組合和組合數

分析:0到9所代表的字元0:"" 1:"" 2:ABC 3:DEF 4:GHI 5:JKL 6:MNO 7:PQRS 8:TUV 9:WXYZ

演算法:例如:23  

              1.show(0,2)-> output[0]=A-> show(1,2)-> 1!=2-> output[1]=D->

              2.k=1 show(2,2)-> 2=len-> 輸出AD-> i+1-> output[1]=E-> show(2,2)-> 2=len-> 輸出AE i=2-> output[1]=F->                             show(2,2)-> 2=len-> 輸出AF

             3.再回到k=0-> i=1 output[0]=ch[0][1]=B  輸出BD,BE,BF i=2 輸出CD,CE,CF

程式碼實現:

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

const char ch[10][10]={ //用陣列存放0到9所表示的字元
	"",//0
	"",//1
	"ABC",//2 
	"DEF",//3
	"GHI",//4
	"JKL",//5
	"MNO",//6
	"PQRS",//7
	"TUV",//8
	"WXYZ"//9 
	};
const int total[10]={0,0,3,3,3,3,3,4,3,4}; //各個數字代表的字元總數構成的陣列 
char input[20];	//儲存輸入電話字元陣列 
char output[20];	//輸出可能字元組合 

void show(int k,int len){  	
	if(k==len){ 
		output[len]='\0';  //設為結束標誌,輸出 
	    printf("%s\n",output);
		return ;
	}
	for(int i=0;i<total[input[k]];i++){ 
		output[k]=ch[input[k]][i];
		show(k+1,len);
	}	
}

int main(){
	printf("請輸入電話號碼:\n");
	scanf("%s",input); //輸入電話字元陣列 
	int len=strlen(input);
	int number[20];
	int sum=1;
	for(int i=0;i<len;i++){
		 input[i]-='0'; //char型別轉換成int陣列 
		sum*=total[input[i]];
	}
	show(0,len);
	printf("總的組合數:%d\n",sum);
	return 0;
}

四、日本著名數學遊戲專家中村義作教授提出這樣一個問題:父親將2520個桔子分給六個兒子。分完 後父親說:“老大將分給你的桔子的1/8給老二;老二拿到後連同原先的桔子分1/7給老三;老三拿到後連同原先的桔子分1/6給老四;老四拿到後連同原先的桔子分1/5給老五;老五拿到後連同原先的桔子分1/4給老六;老六拿到後連同原先的桔子分1/3給老大”。結果大家手中的桔子正好一樣多。問六兄弟原來手中各有多少桔子?

分析:每個兒子的橘子數目有兩種,原有的和現有的,除了老大,其他的兒子原有的+別人給的-給別人的=現有的=平均數,老大是先分給其他人在得到,其他人都是得到再分出去。

演算法:If(i=7)

                Return0;

           Elseif(i = 1)

                 x = (420 - y) / 7 * 8;

                 y=x/8;

                 return f(i+1);

          Elseif(i>1)

                  x = 420 * (9 - i) / (8 - i) - y;

                  y = (x + y) / (9 - i);

                  return f(i+1);

程式碼實現:

#include <stdio.h>
#include "iostream"
using namespace std;
 
//x表示每個人手裡的橘子數,y表示從別人那得到的橘子數 ,老六分給老大210個橘子 
int x  ,y = 210;  
int Number(int i)
{
	if(7 == i)
	{
	}
	else if(1 == i) //老大是先分出去再得到 
	{
		x = (420 - y) / 7 * 8;   //420為老大最後手裡的橘子數 
		cout << "老大原本有" << x << "個橘子。" << endl;
		y = x / 8;   //計算老大分出去的橘子數 
		return Number(i + 1);
	}
	else if(i > 1)  //其他人都是先得到再分出去 
	{
		x =  420 * (9 - i) / (8 - i) - y; //計算手裡原本有多少橘子 
		cout << "老" << i << "原本有" <<x << "個橘子。"<< endl;;
		y = (x + y) / (9 - i);  // 計算得到橘子後再分出去的橘子數 
		return Number(i + 1);
	}
	
}
void main()
{
	Number(1);
}