遞迴演算法的練習
一.一個人趕著鴨子去每個村莊賣,每經過一個村子賣去所趕鴨子的一半又一隻。這樣他經過了七個村子後還剩兩隻鴨子,問他出發時共趕多少隻鴨子?經過每個村子賣出多少隻鴨子?
1.題目分析
經過7個村莊後還剩兩隻鴨子,每經過一個村莊賣當前鴨子的一半加一隻,所以遞迴體是經過前一個村子的鴨子數除以2再減去1就是到達下一個村子的時候的鴨子數,所以要想求在第一個村子的鴨子數,必須從後往前推。
2.演算法構造
當村子數i=0,鴨子數number=2;當村子數0<i<7,經過第i個村子前的鴨子數number=(number+1)*2,在經過第i 個村子時賣的鴨子數m=number/2+1;
3.演算法實現
見檔案sellduck.c
#include<stdio.h> /* *author:軟工1604 徐於敏 16408070731 *date:2018-11-15 *description:一個人趕著鴨子去每個村莊賣,每經過一個村子賣去所趕鴨子的一半又一隻。這樣他經過了七個村子後還剩兩隻鴨子,問他出發時共趕多少隻鴨子?經過每個村子賣出多少隻鴨子? *function:sellduck()函式定義了1個全域性變數i代表村子的數量,通過遞迴實現了計算出發時的鴨子數量 *version:0.1 */ int number=2;//最後的鴨子數量 int m;//用來記錄經過每個村子賣出的鴨子數量 int main() { sellduck(7); } int sellduck(int i) { if(0==i)//i為0時候結束 { printf("他出發時一共趕了%d只鴨子",number); } else{ number=(number+1)*2; //計算在經過第i個村子前的鴨子數number m=number/2+1; //計算在經過第i 個村子時賣的鴨子數m printf( "經過第%d個村子時,他賣出%d只鴨子。\n",i,m); i--;//村子數量-1 return sellduck(i); } }
4.執行結果
二.角谷定理。輸入一個自然數,若為偶數,則把它除以2,若為奇數,則把它乘以3加1。經過如此有限次運算後,總可以得到自然數值1。求經過多少次可得到自然數1。
如:輸入22,
輸出 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
STEP=16
1.題目演算法分析
先判斷輸入的數字是偶數還是奇數,是偶數除以2,是奇數乘以3加1,如此反覆呼叫自身,每做完一次步數+1,並輸出此時的數字,最後得到得到的數字為1,此時遞迴結束
2.演算法實現
見solvejiaogu.c
#include<stdio.h> /*author:軟工1604 徐於敏 16408070731 *date:2018-11-15 *description:.角谷定理。輸入一個自然數,若為偶數,則把它除以2,若為奇數,則把它乘以3加1。 *經過如此有限次運算後,總可以得到自然數值1。求經過多少次可得到自然數1。 *function:定義一個solve()函式,n代表一開始輸入的自然數,step代表步數,通過遞迴實現角谷定理 *version:0.1 */ int main() { int a; printf("輸入一個自然數:"); scanf("%d",&a); solve(a,1); } int solve(int n,int step) { if(n%2==0){//判斷是否為偶數,是偶數除以2 n=n/2; printf("%d\n",n); step++;//步數+1 } else {//否則是奇數,將他乘以3加1 n=n*3+1; printf("%d\n",n); step++;//步數+1 } if(n==1){ printf("總的步數是%d次",step); } if(n!=1){//若當前得到的數字為1,結束遞迴,否則繼續 solve(n,step); } }
3.執行結果
三.電話號碼對應的字元組合:在電話或者手機上,一個數字如2對應著字母ABC,7對應著PQRS。那麼數字串27所對應的字元的可能組合就有3*4=12種(如AP,BR等)。現在輸入一個3到11位長的電話號碼,請打印出這個電話號碼所對應的字元的所有可能組合和組合數。
1.題目分析
2對應ABC,3對應DEF,4對應GHI,5對應JKL,6對應MNO,7對應PQRS,8對應TUV,9對應WXYZ,1和0對應空。
2.演算法構造
當輸入一個數字時,返回這個數字所有可能性的組合。遞迴體是當輸入一串數字,每個數字代表不同的字串,返回最後一個數字跟前面已產生的字串進行組合,所以首先應該建一個數組,用來存放每個數字代表的字串組合,然後在建一個數組,用來存放每個字串的長度,在函式中,先進行判斷是否是最後一位,然後根據判斷執行函式。
3.演算法實現
見phone.cpp
/*
*author:軟工1604 徐於敏 16408070731
*date:2018-11-15
*description:電話號碼對應的字元組合:在電話或者手機上,一個數字如2對應著字母ABC,7對應著PQRS。那麼數字串27所對應的字元的可能組合就有3*4=12種(如AP,BR等)。現在輸入一個3到11位長的電話號碼,請打印出這個電話號碼所對應的字元的所有可能組合和組合數。
*function:通過遞迴函式tellphone實現
*version:0.1
*/
#include<iostream>
using namespace std;
char* phone[10]={"","","ABC","DEF","GHI","JKL","MNO","PQRS","TUV","WXYZ"};//陣列phone用來存放數字對應的字母
int num[10]={0,0,3,3,3,3,3,4,3,4};//陣列num用來存放每一個數字對應的字母的數量
char input[15];//陣列input存放輸入的電話號碼
char output[15];//陣列ouput存放輸出的組合
void tellphone(int n,int len)
{
if(n == len)
{
cout<<output<<endl;
}
for(int i=0; i<num[input[n]]; i++)
{
output[n] = phone[input[n]][i];
tellphone(n+1,len);
}
}
int main()
{
int len;
printf("輸入一個3到11位長的電話號碼:");
scanf("%s",input);
printf("該電話號碼所對應字元的所有可能的組合是:\n");
len=strlen(input);//統計輸入的電話號碼的長度
int count = 1;
for(int i=0; i<len; i++)//計算組合數量
{
input[i] -= '0';
count *= num[input[i]];
}
tellphone(0,len);//呼叫函式
cout<<"組合數:"<<count<<endl;///輸出組合數量
return 0;
}
3.執行結果
四.日本著名數學遊戲專家中村義作教授提出這樣一個問題:父親將2520個桔子分給六個兒子。分完 後父親說:“老大將分給你的桔子的1/8給老二;老二拿到後連同原先的桔子分1/7給老三;老三拿到後連同原先的桔子分1/6給老四;老四拿到後連同原先的桔子分1/5給老五;老五拿到後連同原先的桔子分1/4給老六;老六拿到後連同原先的桔子分1/3給老大”。結果大家手中的桔子正好一樣多。問六兄弟原來手中各有多少桔子?
1.題目分析
每個兒子拿到的橘子數目分別是原有的和現有的,除了老大,其他的兒子原有的+別人給的-給別人的=現有的=平均數,所以,可以得出原有的=現有的+給別人的-別人給的。
2.演算法構造
當老幾n>6,結束;當0<n<6時,算出分給下一個人的桔子數,下一個人的桔子數,下一人加上之前的桔子數的總數,接著一個個呼叫實現
3.演算法實現
見orange.cpp
/*
*author:軟工1604徐於敏16408070731
*date:2018-11-15
*description:日本著名數學遊戲專家中村義作教授提出這樣一個問題:父親將2520個桔子分給六個兒子。分完 後父親說:“老大將分給你的桔子的1/8給老二;老二拿到後連同原先的桔子分1/7給老三;老三拿到後連同原先的桔子分1/6給老四;老四拿到後連同原先的桔子分1/5給老五;老五拿到後連同原先的桔子分1/4給老六;老六拿到後連同原先的桔子分1/3給老大”。結果大家手中的桔子正好一樣多。問六兄弟原來手中各有多少桔子?
version:0.1
*/
#include<iostream>
using namespace std;
int orange(int n,int before, int after,int m )//n是老幾,before是之前的數量,after是之後的數量,m是從八分之一開始的分桔子的比例
{
if(n>6)//結束條件
{
return 0;
}
else
{
printf("老%d原有的桔子數:%d\n",n,before);
int givenum = after/m;//分給下一個人的桔子數
int nextBnum = 420*(m-1)/(m-2)-givenum;//下一個人的桔子數
int afterGetnum = nextBeforenum+givenum;//下一人加上之前的桔子數的總數
return orange(n+1,nextBeforenum,afterGetnum,m-1);
}
}
int main()
{
orange(1,240,240,8);
}```
4.執行結果
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20181117154556919.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTIyMDgzMw==,size_16,color_FFFFFF,t_70)
五.歸納總結
遞迴的解決首要就是,找到遞迴體和遞迴出口,將大問題分解成小問題,將小問題分解成可以直接解決的問題,在往上推,最終解決問題。