水手分椰子——迭代法、遞迴解題
阿新 • • 發佈:2018-11-26
題目內容:
n(1< n <=5)個水手在島上發現一堆椰子,先由第1個水手把椰子分為等量的n堆,還剩下1個給了猴子,自己藏起1堆。然後,第2個水手把剩下的n-1堆混合後重新分為等量的n堆,還剩下1個給了猴子,自己藏起1堆。以後第3、4個水手依次按此方法處理。最後,第n個水手把剩下的椰子分為等量的n堆後,同樣剩下1個給了猴子。請用迭代法程式設計計算並輸出原來這堆椰子至少有多少個,n的值要求從鍵盤輸入。若輸入的n值超出要求的範圍,程式輸出”Error!”。
提示:分成的等量的堆數應該與水手的數量一致.
程式執行結果示例1:
Input n(1 < n <= 5):
5↙
y=3121.
程式執行結果示例2:
Input n (1 < n <= 5):
7↙
Error!
輸入提示資訊: “Input n(1 < n <= 5):\n”
輸入格式: “%d”
輸出格式:”y=%d\n”
輸入錯誤提示資訊:”Error!\n”
這是一道著名的數學問題,解題通式為:
y=a(a/m)n-1 -db/c
y ── 被分的椰子的總個數.
a ── 每次分的份數,
n ── 總共分的次數.
b ── 每次分a份後的餘數.
c ── 每次分a份後拿走的份數.
d ── 每次分a份後拿走c份後,剩下再分的份數.
m── (a/d)的最大公約數.
迭代法實現
思路:
- 假設現在有五個人分一堆椰子,那麼每個人都會分一次椰子,我們可以得知人數就是分椰子的次數
- 假設第一個人還沒分的時候椰子總共有y1個,那麼第一個人分了之後,椰子總數y2=(y1-1)*(4/5);如果已知y2求y1,那麼y1=(y2*5)/4+1。
- 我們知道椰子都是一個一個的,這就說明椰子數量是整數,判斷一個數是否是符合條件,我們僅需要判斷每次它被分之後是不是整數就ok。
- 為減少時間複雜度,我們選擇還原數量的方式迭代,設一個迴圈,迴圈變數為分了n次之後每一份的椰子數量,向上還原,判斷還原n層的過程中每次椰子的數量仍然是否是整數,如果不是,繼續外層迴圈,直到找到一個數能夠進行n次內層迴圈為止。
程式程式碼(C語言):
#include<stdio.h> int main() { int i, j, total, n; printf("Input n(1<n<=5):\n"); scanf("%d", &n); if (n <= 1 || n > 5) { printf("Error!\n"); } else { i = 1; while(1) { total = i; for(j = 0; j < n; j++) { total = total * 5; if(total % 4 != 0) { break; } total = total / 4; total += 1; } if(j == n) { break; } i++; } printf("y=%d\n", total); } return 0; }
遞迴實現
思路:
寫一個函式模擬分椰子操作,傳入分的椰子數量和分的人數,判斷椰子數量是否足夠支援到最後一個人分完,如果能返回一個真值,如果不能返回一個假值。
程式程式碼(C語言):
#include <stdio.h>
int divide(int n, int m);
static int people;
int main()
{
int i;
int n;
printf("Input n(1<n<=5):\n");
scanf("%d", &n);
people = n;
if (n <= 1 || n > 5)
{
printf("Error!\n");
}
else
{
for (i = 1; ; i++)
{
if (divide(i, n))
{
printf("y=%d\n", i);
break;
}
}
}
return 0;
}
int divide(int n, int m)
{
if (n / people == 0 || n % people != 1)
return 0;
if (m == 1)
return 1;
return divide(n - n / people - 1, m - 1);
}