問題描述
小明的數學老師出了一題函數計算的家庭作業,由於筆算的過程非常複雜,請你寫一個程式協助小明以及班上的其他同學進行驗算,以確定計算的結果是正確的。老師所出的題目是這樣的:給定一個整數 x,請求出函數 f 的值為何?

輸入格式(標準輸入)
直接從標準輸入(鍵盤)輸入一整數 x,-300 < x < 300。
輸出格式(標準輸出)
請將計算過後函數 f 的值直接輸出至標準輸出(螢幕)。
輸入範例1
3
輸出範例1
-1
輸入範例2
-2
輸出範例2
-4
輸入範例3
-21
輸出範例3
-1307
解題思考
乍看之下題目還滿簡單的,因此就直接照著題目的定義做吧。
然後接下來你會發現:大部分的測試資料程式都跑不動!這算是題目設計的小陷阱,假如就這樣照著題意實現,就會因為遞迴的呼叫,導致堆疊過多以致於溢位。
因此,在撰寫程式前,我們得先對題目做簡易的分析。
首先看到 f(x),很明顯可以發現,其麻煩在於要比較 x 與 h(x) 的大小。因為 g(x) 的計算相對容易,在這裡,我選擇要簡化的是 x > h(x) 的情況。
又可以發現若且惟若 -3 < x < 2 或 x > 4 時,x > h(x) (可以自己手動計算看看),因此我們從這個範圍的數字開始分析(我們先手動算出 f(-1) = 1, f(4) = -1):
f(0) = f(-1) - h(1) = 1 - h(1)
f(1) = f(0) - h(1) = f(-1) - h(0) - h(1) = 1 - h(0) - h(1)
由上式整理可得,在 -3 < x < 2 時:
f(x) = 1 - (h(0) + h(1) + ... + h(x))
f(5) = f(4) - h(5) = -1 - h(5)
f(6) = f(5) - h(6) = f(4) - h(5) - h(6) = -1 - h(5) - h(6)
f(7) = f(6) - h(7) = f(5) - h(6) - h(7) = f(4) - h(5) - h(6) - h(7) = -1 - h(5) - h(6) - h(7)
同樣整理可得,在 x > 4 時:
f(x) = -1 - (h(5) + h(6) + ... + h(x))
藉由這樣展開,就省去許多遞迴呼叫 f(x - 1) 的狀況(尤其在 x 相當大的情況)。(不過在這裡我可能還做複雜了,假如有誰有更好的方法,歡迎提出。)
接著,我們看到 h(y) 在 y 大於等於 2 的情況:
h(2) = 2
h(3) = 5
h(4) = 5
h(5) = -1
h(6) = -1
h(7) = 2
h(8) = 2
h(9) = 5
h(10) = 5
h(11) = -1
h(12) = -1
h(13) = 2
這裡,我們可以發現,h(y) 每六個數字為一個循環週期,因此,我們只要根據 y 除以 6 的餘數,就能夠判斷 h(y) 的結果了。
最後,g(z) 就照著題目的定義實現即可。
參考解答(C)
#include <stdio.h>
#include <stdlib.h>
int f(int), h(int), g(int);
int main(void)
{
int x;
printf("請輸入一個整數X:");
scanf("%d", &x);
printf("函數計算結果:%d\n", f(x));
system("pause");
}
// f(x)的函數
int f(int x)
{
int i, ret;
if (x > h(x))
{
i = x < 5 ? 0 : 5;
ret = x < 5 ? 1 : -1;
for (; i <= x; i++)
{
ret -= h(i);
}
return ret;
}
else if (x < h(x))
{
return f(g(x)) - g(x);
}
else
{
return 1;
}
}
// h(y)的函數
int h(int y)
{
if (y < 2)
{
return -1;
}
else
{
switch(y % 6)
{
case 2:
case 5:
return 2;
case 3:
case 4:
return 5;
default:
return -1;
}
}
}
// g(z)的函數
int g(int z)
{
if(z <= 2)
{
return z * z - 1;
}
else
{
return 2;
}
}
0 回覆:
張貼留言