C語言遞迴解決5人分魚問題
問題描述A、B、C、D、E這5個人合夥夜間捕魚,凌晨時都已經疲憊不堪,於是各自在河邊的樹叢中找地方睡著了。第二天日上三竿時,A第一個醒來,他將魚平分為5份,把多餘的一條扔回河中,然後拿著自己的一份回家去了;B第二個醒來,但不知道A已經拿走了一份魚,於是他將剩下的魚平分為5份,扔掉多餘的一條,然後只拿走了自己的一份;接著C、D、E依次醒來,也都按同樣的辦法分魚。問這5人至少合夥捕到多少條魚?每個人醒來後所看到的魚是多少條?
問題分析
假設5個人合夥捕了x條魚,則“A第一個醒來,他將魚平分為5份,把多餘的一條扔回河中,然後拿著自己的一份回家去了”之後,還剩下4(x-1)/5條魚。
這裡實際包含了一個隱含條件:假設Xn為第n(n=1、2、3、4、5)個人分魚前魚的總數,則(Xn-1)/5必須為正整數,否則不合題意。(Xn-1)/5為正整數即(X〜l)mod5=0必須成立。
又根據題意,應該有下面等式:
X4=4(X5-1)/5
X3=4(X4-1)/5
X2-4(X3-1)/5
X1=4(X2-1)/5
則一旦給定X5,就可以依次推算出X4、X3、X2和X1的值。要保證X5、X4、X3、X2和X1都滿足條件(Xn-1)mod5=0,此時的X5則為5個人合夥捕到的魚的總條數。顯然,5個人合夥可能捕到的魚的條數並不唯一,但題目中強調了 “至少”合夥捕到的魚,此時題目的答案唯一。該問題可使用遞迴的方法求解。
程式設計
在main()函式中構建一個不定次數的do-while迴圈。定義變數x表示5個人合夥可能捕到的魚的條數,可以取x的最小值為6,讓x值逐漸增加,x每一次取值,都增加5,直到找到一個符合問題要求的答案。由於題目中問“這5人至少合夥捕到多少條魚”,而我找到的第一個x值就是5個人至少捕到的魚的總條數。
通過這個迴圈,就可以對每一個的可能情況進行檢查。當然,是通過呼叫分魚的遞迴函式來進行檢查的。
分魚的遞迴函式如下:
fish()函式中包含了兩個引數:n和x。n表示參與分魚的人數,x表示n個人分魚前魚的總條數。這兩個引數都是由main()函式中傳遞進來的。
根據前面的分析,當n=5時,(x-1)mod5==0必須成立,否則該x值不是滿足題意的值,退出fish()函式,返回到main()函式,main()函式中再傳遞新的x值到fish中進行檢驗。如果(x-1)mod5==0條件成立,則要判斷n=4時,(x-1)mod5=0條件是否成立,需要注意的是,此時的形參x是4個人分魚前魚的總條數,即f(5,x)遞迴呼叫f(4,(x-1)/5*4)。這樣依次進行下去,直到n=1時,(x-1)mod5==0條件仍成立,則說明開始從main()函式中傳遞進來的x值是符合題意要求的一個值,可以逐層從遞迴函式中返回,每次返回值都為1,直至返回到main()函式。
下面是完整的程式碼:
#include<stdio.h>
/*分魚遞迴函式*/
int fish(int n, int x)
{
if((x-1)%5 == 0)
{
if(n == 1)
return 1; /*遞迴出口*/
else
return fish(n-1, (x-1)/5*4); /*遞迴呼叫*/
}
return 0; /*x不是符合題意的解,返回0*/
}
int main()
{
int i=0, flag=0, x;
do
{
i=i+1;
x=i*5+1; /*x最小值為6,以後每次增加5*/
if(fish(5, x)) /*將x傳入分魚遞迴函式進行檢驗*/
{
flag=1; /*找到第一個符合題意的x則置標誌位為1*/
printf("五個人合夥捕到的魚總數為%d\n", x);
}
}
while(!flag); /*未找到符合題意的x,繼續迴圈,否則退出迴圈*/
return 0;
}
執行結果:
五個人合夥捕到的魚總數為3121
知識點補充
本題還可以使用“遞推法”來求解。下面先對遞推法做下簡介。
遞推法:利用問題本身所具有的遞推關係來求解。所謂的遞推關係指的是:當得到問題規模為n-1的解後,可以得出問題規模為n的解。因此,從規模為0或1的解可以依次遞推出任意規模的解。
下面是完整的程式碼:
#include<stdio.h> /*分魚遞迴函式*/ int fish(int n, int x) { if((x-1)%5 == 0) { if(n==1) return 1;/*遞迴出口*/ else return fish(n-1, (x-1)/5*4);/*遞迴呼叫*/ } return 0;/*x不是符合題意的解,返回0*/ } int main() { int fish[6], i; fish[5]=6; while(1) { for(i=4; i>0; i--) { if(fish[i+1]%4!=0) break; fish[i]=fish[i+1]*5/4+1; if(fish[i]%5!=1) break; } if(i == 0) break; fish[5]+=5; } for(i=1; i<=5; i++) printf("fish[%d]=%d\n", i, fish[i]); return 0; }
執行結果:
fish[1]=3121
fish[2]=2496
fish[3]=1996
fish[4]=1596
fish[5]=1276
Linux公社的RSS地址 : ofollow,noindex" target="_blank">https://www.linuxidc.com/rssFeed.aspx
本文永久更新連結地址: https://www.linuxidc.com/Linux/2018-10/154997.htm