K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]

新規投稿 | 開設者ホームページへ戻る | ヘルプ

[295] 誰か助けてください
投稿者:マキバオー
2007/02/20 02:13:25

最近C言語を始めたのですが、この問題がどうしても解けません。誰かといてください。お願いします(>_<) 1.ある銀行では毎期末に預金残高に対して5%の利率で利息がつく.この銀行に,例えばa万円を一期間預金すると,期末には1.05×a万円の預金残高になる. 第1期の初めに,Aさんはこの銀行にb万円の預金を持っている.Aさんは,まずb万円から第1期分m万円を引き出す.残りの預金に対し第1期末に5%の利息がつく.ここで,b > mとする.第2期目からも毎期初めにこの預金からm万円ずつを引き出す.ただし,預金残高がm万円に満たないときには,その全額を引き出すものとする. Aさんの預金残高がn期間にわたって0円とならないために必要な第1期初めの預金額「b」を計算したい.期間「n」と毎期の引き出し額「m」を入力して,上の条件を満たす最小の「b」を求めるプログラムを作れ.なお,単位は「万円」とする.また,n >= 2 とする.
[この投稿を含むスレッドを表示] [この投稿を削除]
[296] Re:誰か助けてください
投稿者:(ぱ)
2007/02/20 02:13:25

>最近C言語を始めたのですが、この問題がどうしても解けません。誰かといてください。お願いします(>_<)  宿題は自分でやるべきでしょう。
[この投稿を含むスレッドを表示] [この投稿を削除]
[298] Re:誰か助けてください
投稿者:どぅ
2007/02/20 02:13:25

>>最近C言語を始めたのですが、この問題がどうしても解けません。誰かといてください。お願いします(>_<) > > 宿題は自分でやるべきでしょう。 初めまして、どぅと申します。 前橋さまの「C言語 ポインタ完全制覇」と「Java謎+落とし穴徹底解明」によって蒙を啓かれた者です。まだ理解できていないところもありますが、この二冊には大変お世話になっております(現在進行形)。 さて、本題ですが、宿題は自分でやるべきで、それがマキバオーさんの為だと思いますし、それゆえ(ぱ)さまは流石思いやりのある対応をされたなぁと思うのですが、残念ながら私は利己的で、マキバオーさんの為にはならないと知りながら、申し訳ないけど自分の興味の為に課題をやってしまいました。情けは人の為ならず(←ダブルミーニング!)。尤も正しい答えに到達しているかは分かりませんが。 この手の問題は、半分数学ですね。より正確に言うと、ドコまで数学で解いて、ドコからプログラムにやらせるか。これは連続的にスペクトルをなしていて、一方の端が、「全部人間様が数学を駆使して計算する」反対側の端が「全部プログラムにしてコンピュータが計算する」になってます。つまり大ざっぱにいうと、 1.全部数学で人間様がやる。 2.半分数学で人間様がやって、半分プログラムにしてコンピュータがやる。 3.全部プログラムにしてでコンピュータがやる。 の3パターンに分かれると思います。おそらく出題者は2を期待してるんじゃないかなーと思いますが、どうなんでしょ?1で解くと多分ダメなんでしょうね^^;とりあえず「おそらくこんな解が期待されてるんだろうなぁ」てな2の解を示して、その次に3の解を書いてみます。 ■パターン2 まず、n期目で残高があれば良い。そんで、n期目の残高は、nとmとb(と利率1.05)で決まりますね。つまりn期目の残高はn, m, bの関数になるので Z(n, m, b)と書けると。それが残っていると言うことは、 Z(n, m, b) > 0 となると。この不等式をbについて解けば良いわけですね。じゃあZ(n, m, b)って何なのよ? こういうのはとりあえず普通1期目、2期目、3期目、ぐらいまで具体的に求めてみると何か見えてくる可能性があります。と言うわけで、各期の残高を求めてみると。。。 1期目:1.05(b - m) = 1.05b - 1.05m 2期目:1.05(1.05b - 1.05m - m) = 1.05^2b - 1.05(2.05)m 3期目:1.05(1.05^2b - 1.05(2.05)m - m) = 1.05^3b - 1.05(1.05(2.05) + 1)m ここら辺までくると何かが見えてきますね!?つまりi期目の残高は、 1.05^ib - ???m となりそうです。???のところをよーく見ると、 ???は、前期の???に1を足して、1.05倍する となってそうです。つまり、i期の???をY(i)とすると、 Y(i+1) = 1.05(Y(i) + 1) Y(1) = 1.05 と言えそうです。これ、漸化式ってやつだけど、どうやら解くのは面倒そうですね。。 #根性入れれば解けるので、そうすれば「1」のパターンになる!! とりあえず、Y(i)はそのまま(1から順番にやれば求まりそうだし)とすると、i期における残高は、 X(i)b - Y(i)m ただし、X(i) ,Y(i)は次の通り、 X(i) = 1.05^i Y(i)は、次の漸化式を満たす Y(i+1) = 1.05(Y(i) + 1) Y(1) = 1.05 で表されます。これがn期で残っていると言うことは、 X(n)b - Y(n)m > 0 と言うことになりますので、bについて解くと(X(n) > 0に注意して) b > Y(n)m / X(n) となります。Y(n)は漸化式にしたがって1から順番に計算していけば求まりますが、めんどいなぁ。誰かやってくれないかなぁ。。。人間様が考えるのはここまで。あとはコンピュータにやってもらいまひょ。ついでにX(n) = 1.05^nも計算してもらいます。 で、プログラムは次の通り。解に自信がなかったので、求まったbの値で本当に良いのか、各期残高を順に表示して検算もしてます。求まるbはぎりぎりの値なので、n年目には残高が0円になってしまいますが、bはそれより大きければ良いということで。。。 ちなみに、銀行でどの有効桁数で情報を持っているのか、つまり0.1銭とかにも利子が付くのか!?は気にしてません。doubleの有効桁数の範囲で計算してます。 あと、math.hが入ってますので、コンパイル時に-lmを忘れずに!(←なんて親切なんだ!?) #include <stdio.h> #include <math.h> #include <stdlib.h> int main(int argc, char** argv){ int n = 0; int m = 0; double x_n = 0.0; double y_n = 1.05; double b = 0.0; double zandaka = 0.0; int ii; /* パラメータチェック */ if ( argc != 3 ){ printf("usage %s n m\nn:期間 m:引き出し額\n", argv[0]); return 0; } /* パラメータ取得 */ n = atoi(argv[1]); /* 期間 n */ m = atoi(argv[2]); /* 引き出し額 m */ /* i期における残高: ( X(i) * b ) - ( Y(i) * m ) * ただし、 * X(i) = 1.05^i, * Y(i) : Y(i+1) = 1.05 * ( Y(i) + 1 ), Y(1) = 1.05 * n期において0円以上あるためには * (X(n) * b) - (Y(n) * m) > 0 * これを bについて解くと、 * b > Y(n) * m / X(n) */ /* X(n)を求める */ x_n = pow(1.05, n ); /* Y(n)を求める。ここがキモ */ for ( ii = 2; ii <= n; ii++ ){ y_n = 1.05 * ( y_n + 1 ); } /* b(の下限)を求める */ b = (y_n * m) / x_n; /* 残高の変化の様子を表示(検算) */ zandaka = b; for (ii = 1 ; ii <= n; ii++){ zandaka = 1.05 * ( zandaka - m ); printf("%3d: %f\n", ii, zandaka); } /* 表示 */ /* printf("X(n) = %f\n", x_n); */ /* printf("Y(n) = %f\n", y_n); */ printf("n = %d\n", n); printf("m = %d\n", m); printf("b > %f\n", b); return 0; } ■パターン3 次に、人間様は何も考えないで、全部プログラムでコンピュータにやらせるパターンをやってみます。 b=1万円から初めて、n期目でも残高が残っているまで、bを1万円ずつインクリメントしていきます。なので、精度が1万円単位になってます。1円単位の精度が欲しい場合は0.0001万円から初めて0.0001ずつインクリメントすれば良いでしょう。10000倍遅くなりますが・・・ 言うまでもなく、このアルゴリズムは余りにバカ正直で(特に1円単位なると影響大)、普通はちょっと工夫すると思いますが、「人間様は何も考えない」パターンということで。 これをどうやって高速化するか(スペクトルをちょっと人間様寄りにする)は、マキバオーさんの宿題と言うことで。。。もしかしたらそれが求められている解かも? #include <stdio.h> #include <stdlib.h> int main(int argc, char** argv){ double b = 0; int n = 0; int m = 0; double zandaka; int ii; if ( argc != 3 ){ printf("usage %s n m\nn:期間 m:引き出し額\n", argv[0]); return 0; } n = atoi(argv[1]); /* 期間 n */ m = atoi(argv[2]); /* 引き出し額 m */ /* n期目でも残高が残るまでbをインクリメントしていく */ for ( b = 1 ;zandaka <= 0 ; b += 1){ /* 残高を、残っている限り、最大n期目まで求める*/ zandaka = b; for (ii = 1 ; ii <= n && zandaka > 0; ii++){ zandaka = 1.05 * ( zandaka - m ); } } /* 残高の変化の様子を表示(検算) */ zandaka = b; for (ii = 1 ; ii <= n && zandaka > 0; ii++){ zandaka = 1.05 * ( zandaka - m ); printf("%3d:%f\n", ii, zandaka); } /* 表示 */ printf("n = %d\n", n); printf("m = %d\n", m); printf("b > %f\n", b); return 0; } ソースは無保証です!!! ただ、バグのご指摘、ご批評など頂ければ幸いです。
[この投稿を含むスレッドを表示] [この投稿を削除]