つぶれるボール

解決


もももじゃむ  2010-07-06 03:32:24  No: 71784  IP: 192.*.*.*

●●●●●● と1列に並んだボールがありまして、これを

●●●●●●←←の矢印の方向からぎゅっとつぶします。

この時、各ボールの幅は左隣のボールの幅の n% の幅になります。
つまり、つぶれていないボールの幅が w の時、各ボールの幅は左から順番に、
w * n, w * n * n, w * n * n * n,  ......となっていきます。

つぶれていないボールの幅が w とするなら、x個並んだボールの総合的な幅 t は t = w * x になります。


これで、つぶした状態のボールの総合的な幅 tw が与えられた時、各ボールの幅はそれぞれどのように求めたらいいですか。

tw < t の関係が成り立つ事は保証します。
また、n%, x, t, w はそれぞれ事前にわかっています。

分かりにくい質問かもしれませんが、よろしくおねがいします。

編集 削除
tetrapod  2010-07-06 08:51:23  No: 71785  IP: 192.*.*.*

要するに代数的に解けない(可能性のある)式を解きたいだけでしょ。
ボール全部の幅 tw は圧縮率 n に対して単調関数なので、
ニュートン法でも二分法でも問題ないぢゃん。

編集 削除
ryo  2010-07-06 09:51:45  No: 71786  IP: 192.*.*.*

ここは、VCをメインとしてるプログラミングなどを扱ってる掲示板だから
質問する場所を間違えていますよ

編集 削除
もももじゃむ  2010-07-06 10:23:57  No: 71787  IP: 192.*.*.*

ニュートン法・二分法ちょっと調べてみましたが、さっぱり解りません。

とりあえず二分探索っぽくやってみました。

main(void) 

  int i;

  int x = 6;
  int w = 30;
  int t = x * w;
  int tw = 150;
  double tmp, total = 0;

  double s = 0.0, e = (t - tw) / (double)x, m = e / 2;

  do{
    tmp = 0;
    for(i = 1;i<=x;i++){
      tmp += w * m * i;
    }
    if((int)tmp == tw) break;

    if(tmp > tw) e = m;
    else s = m;
    m = s + (e - s) / 2;
  }while(tw != (int)tmp);

  for(i = 1;i<=x;i++){
    total += w * m * i;
    printf("%d個目 幅=%f, total=%f\n", i, w * m * i, total);
  }
}


言われてみれば、ただのC言語の問題にVCなんて関係ないですね。
BCCでもGCCでもいいわけですし。

もうちょっといろいろと突き詰めたいところですが、これで解決とさせていただきます。

また機会があればそのときはよろしくお願いします。

編集 削除
もももじゃむ  2010-07-06 10:25:08  No: 71788  IP: 192.*.*.*

すみません。  解決チェック入れ忘れてました。

編集 削除
tetrapod  2010-07-06 11:05:01  No: 71789  IP: 192.*.*.*

別に VC++ 特化な質問限定でなくてもいいと思う。以前にもいっぱいあったし。
せっかく作ったので上げておく。手抜きいっぱいだけど。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define ball_width 100.0
#define ball_count 6

double calc_total_width(double pressure) {
    double ball=ball_width*pressure;
    double total_width=0;
    int i;
    for (i=0; i<ball_count; ++i) {
        total_width+=ball;
        ball*=pressure;
    }
    return total_width;
}

double binary_search(double min, double max, double (*func)(double), double target) {
    double center;
    double e;
    do {
        center=(min+max)/2.0;
        e=func(center)-target;
        if (e<0) min=center; else max=center;
    } while (fabs(e)>0.01);
    return center;
}

int main(int argc, char* argv[]) {
    double target_width=strtod(argv[1], 0);
    printf("%g\n", binary_search(0.0, 1.0, &calc_total_width, target_width));
    return 0;
}

編集 削除
ryo  2010-07-06 12:41:59  No: 71790  IP: 192.*.*.*

>言われてみれば、ただのC言語の問題にVCなんて関係ないですね。
俺は、そんなこといってないし、そんなことも思ってない

そもそも、「C言語で開発してる」なんて情報を、書いてないくせに
あたかも俺がそれを元に発言したかのように解釈しないでくれ

最初の質問には
開発環境も、開発言語も、プログラムに関する疑問も記述も単語も何もない
数学の問題にしか見えない

唯一、掛け算が*で表現されてるぐらいか

編集 削除
maru  2010-07-06 13:33:18  No: 71791  IP: 192.*.*.*

> 数学の問題にしか見えない
数学の問題ですよね。

> つまり、つぶれていないボールの幅が w の時、各ボールの幅は左から順番> に、
> w * n, w * n * n, w * n * n * n,  ......となっていきます。
初項w、公比n(n/100と書くべきかな)のx番目までの等比数列。
等比数列の和(等比級数)は初項a、公比r、項数nの時
 S = a(1-rのn剰)/(1-r)
となることがわかっている。
この関係を元の問題に当てはめると、
 tw = w(1-nのx剰)/(1-n)
という関係式がわかる。これに具体的な数値を入れていけば
> 各ボールの幅はそれぞれどのように求めたらいいですか。
はすぐに出るような気がするが。つまり、
左端のボールの幅:w = tw(1-n)/(1-nのx剰)
そのとなり:wn = tw*n(1-n)/(1-nのx剰)
以下省略

何か勘違いしてますか?

編集 削除
maru  2010-07-06 14:14:25  No: 71792  IP: 192.*.*.*

間違えた。
> 初項w、公比n(n/100と書くべきかな)のx番目までの等比数列。
初項 w * n だった。
したがって
 tw = w*n*(1-nのx剰)/(1-n)

左端のボールの幅:w * n = tw*(1-n)/(1-nのx剰)
そのとなり:w * n * n = tw*n*(1-n)/(1-nのx剰)

でも何か、問題が変。
> また、n%, x, t, w はそれぞれ事前にわかっています。
> 各ボールの幅は左から順番に、w * n, w * n * n, w * n * n * n,
> 各ボールの幅はそれぞれどのように求めたらいいですか。
そのまま計算できるような気がする。
nは不明なんじゃないかな?

まだ何か勘違いしているのかなぁ。

編集 削除
maru  2010-07-06 14:39:31  No: 71793  IP: 192.*.*.*

さらに言わせてもらえば もももじゃむ さんのプログラムは
> 各ボールの幅は左から順番に、
> w * n, w * n * n, w * n * n * n,  ......となっていきます。
を実現していないように思われます。

> for(i = 1;i<=x;i++){
> total += w * m * i;
> printf("%d個目 幅=%f, total=%f\n", i, w * m * i, total);
> }
> }

w * n, w * n * 2, w * n * 3, ...
ですよね。
これで解決でいいの?

nを求めるのなら、tetrapod さんのプログラムが正しいやり方でしょう。

私が示した tw = w*n*(1-nのx剰)/(1-n) を使う場合でも、n の x 次方程式に
なるので、やはりニュートン法などが必要になるでしょう。

編集 削除