質問です・・・

 投稿者:NINA  投稿日:2008年11月 9日(日)22時54分19秒
  大学の数学の課題で、

「1,2,3,…,n の順に並んでいる数列のなかで、“+”と“=”を入れて式を完成させよ。」

というような、課題がでました。問題の答えの例としては

1+2=3
1+2+3+…+14=15+16+17+…+20 (=105)

という様な感じです。


これを十進BASICで1,000,000桁までくらいの等式をつくれ ということ言われ、やってみたのですが、
BASICを使うのは初めてなので、どんな風にプログラムを作ればいいのかわかりません。

どなたかご指導いただければと思い、投稿させていただきました。
わかるかた、ぜひよろしくお願いします!!
 

Re: 質問です・・・

 投稿者:荒田浩二  投稿日:2008年11月10日(月)14時45分25秒
  > No.77[元記事へ]

NINAさんへのお返事です。

まず、1,000,000桁ではなくn=1,000,000までの間違いですよね。

等式

  1+2+…+(k-1)+k=(k+1)+(k+2)+…+(n-1)+n

を、次のようにnについての2次方程式と考えれば

  (k^2+k)/2=(n^2+n)/2-(k^2+k)/2

nが整数解を持てば等式は成り立ちます。

  FOR k=1 TO 1000000 ~ NEXT k

として、nが整数解を持つか調べればよいのでは。
(1,000,000までに8個ありました)
 

Re: 質問です・・・

 投稿者:NINA  投稿日:2008年11月10日(月)23時39分46秒
  > No.78[元記事へ]

荒田浩二さんへのお返事です。



> NINAさんへのお返事です。
>
> まず、1,000,000桁ではなくn=1,000,000までの間違いですよね。

そうでした。ご指摘ありがとうございます。


> 等式
>
>   1+2+…+(k-1)+k=(k+1)+(k+2)+…+(n-1)+n
>
> を、次のようにnについての2次方程式と考えれば
>
>   (k^2+k)/2=(n^2+n)/2-(k^2+k)/2
>
> nが整数解を持てば等式は成り立ちます。
>
>   FOR k=1 TO 1000000 ~ NEXT k
>
> として、nが整数解を持つか調べればよいのでは。
> (1,000,000までに8個ありました)


とてもわかりやすい解説ありがとうございました!求め方、式の書き方は理解できました。

さっそくやってみたのですが、 (k^2+k)/2=(n^2+n)/2-(k^2+k)/2 と打ったところ、エラーの表示がでてしまいました。
そのまま入力したのがいけなかったのでしょうか??

また、整数解をもつか調べるのはIF文で良いのでしょうか??

教えていただけますでしょうか??
 

Re: 質問です・・・

 投稿者:山中和義  投稿日:2008年11月11日(火)11時10分6秒
  > No.77[元記事へ]

NINAさんへのお返事です。

> 大学の数学の課題で、
> 「1,2,3,…,n の順に並んでいる数列のなかで、“+”と“=”を入れて式を完成させよ。」

別解を紹介しておきます。

●解き方
たとえばN=10の場合、1○2○3○4○5○6○7○8○9○10 と数列ができる。
○(演算記号=を入る場所)の数は、10-1=9個あるから場所の可能性は1~9である。

次に条件を満たす判断方法は、たとえば、3番目とすると
 1○2○3=4○5○6○7○8○9○10
となるから、=で元の数列は「左辺」と「右辺」に2分割される。
したがって、1○2○3 と 4○5○6○7○8○9○10 の2つの等差数列の和を求めて「左辺=右辺」で判断すればよい。
ここでは左辺と右辺の和を求めるのではなく「左辺が全体の和の半分に等しい」ということで条件を満たすと判断する。
Σk=n*(n+2)/2の公式を使ってそれぞれ求める。

ここで、S1=1、S2=1+2、S3=1+2+3、… 、Sn=1+2+3+ … +n、すなわちデータ列{Sn}を考える。
これは左辺の和が順に並んだものである。
したがって、「左辺が全体の和の半分に等しい」は
 この1~n個のデータ列から、Sn/2の値を見つける「探索」の問題
に置き換えることができる。
逐次探索すると毎回の走査が必要で時間がかかる。
S1,S2,…,Snは整列された(小さい順)データ列だから、2分探索が可能である。

●「基本アルゴリズムの課題」としてのサンプル
!OPTION ARITHMETIC decimal_high

LET t0=TIME

DIM S(1000000) !S1,S2,…,Sn
LET S(1)=1
FOR k=2 TO 1000000
   LET S(k)=S(k-1)+k !左辺 1+ … +(k-1)+k の値
NEXT k


LET c=0 !個数
FOR n=1 TO 1000000

   LET key=S(n)/2 !「全体の半分の値」を見つける

   LET L=1 !下限
   LET H=n !上限
   DO WHILE L<=H !逆転したら終了
      LET M=INT((L+H)/2) !中央
      IF S(M)<=key THEN LET L=M+1 !絞り込む
      IF S(M)>=key THEN LET H=M-1
   LOOP
   !!!PRINT n;L;H

   IF L=H+2 THEN !見つかったら
      LET c=c+1
      PRINT c;"個目"

      PRINT "1 + … +";M;"=";M+1; !左辺と=
      IF M<n-1 THEN !整形のため
         PRINT "+ … +";n; !右辺
      END IF
      PRINT "(=";S(M);")" !和
   END IF

NEXT n


PRINT "計算時間=";TIME-t0

END

(実行結果)
 1 個目
1 + … + 2 = 3 (= 3 )
 2 個目
1 + … + 14 = 15 + … + 20 (= 105 )
 3 個目
1 + … + 84 = 85 + … + 119 (= 3570 )
 4 個目
1 + … + 492 = 493 + … + 696 (= 121278 )
 5 個目
1 + … + 2870 = 2871 + … + 4059 (= 4119885 )
 6 個目
1 + … + 16730 = 16731 + … + 23660 (= 139954815 )
 7 個目
1 + … + 97512 = 97513 + … + 137903 (= 4754343828 )
 8 個目
1 + … + 568344 = 568345 + … + 803760 (= 161507735340 )


●「2次方程式を解く」の別解としてのサンプル
FOR k=1 TO 1000000
 nについての2次方程式 n^2+n-2*(k^2+k)=0 を解いて正の整数解を得る
NEXT k
これは、数列{Sk,Sk+1,…}の中から、2*Skを探すことです。
無限個の中を探索できないので、(実際は小さい順に整列しているので途中で中止する)

 Sk,Sk+1,…,Sn-1,Sn,Sn+1,…
         ↑
         2*Sk?
この矢印のの位置を2次方程式を解くことで推定している。


実際どこにデータがあるかは、S=Σk=n*(n+2)/2よりSQR(S)の位置と推定されるので、
上記サンプル同様に数列{S1,S2,…,Sn}でSn/2を探すアプローチは以下のようになる。
!OPTION ARITHMETIC decimal_high

LET t0=TIME


LET c=0 !個数
FOR N=2 TO 1000000

   LET S=N*(N+1)/2 !全部の和

   LET a=INT(SQR(S)) !=が入る箇所の可能性
   FOR k=a TO a+1
      LET L=k*(k+1)/2 !左辺の和

      IF 2*L=S THEN !2*左辺=全部の和なら、条件をみたす
         LET c=c+1
         PRINT c;"個目"

         PRINT "1 + … +";k;"="; !左辺と=
         IF i=N-1 THEN !整形のため
            PRINT k+1;"(=";L;")" !右辺と和
         ELSE
            PRINT k+1;"+ … +";N;"(=";L;")"
         END IF
      END IF
   NEXT k

NEXT N


PRINT "計算時間=";TIME-t0

END
 

Re: 質問です・・・

 投稿者:荒田浩二  投稿日:2008年11月11日(火)18時32分18秒
  > No.79[元記事へ]

NINAさんへのお返事です。


> さっそくやってみたのですが、 (k^2+k)/2=(n^2+n)/2-(k^2+k)/2 と打ったところ、エラーの表示がでてしまいました。


 BASICでは、等号は変数に数値を与えるときに使います(代入文)。

たとえば「LET a=b+3」という文は、変数aに数値式b+3の値を代入するという意味です。(変数bが4ならばaの値は7になります)

左辺は一つの変数でなければいけません。「LET b+3=a」と記述すると文法エラーになります。
(十進BASICのヘルプの[入門][変数][let文]を参照して下さい)


  また、BASICは式の変形や方程式を解くといった数式処理には対応していません。
その部分は自分で解くか、解くためのプログラムを作らなければなりません。

前出の問題で言えば、

  (k^2+k)/2=(n^2+n)/2-(k^2+k)/2

を下のように変形することはBASICはしてくれません。

  n^2+n-2*(k^2+k)=0

この解を求めるのも、そのためのプログラムを作る必要があります。


 下は、2次方程式 a*x^2+b*x+c=0 の解の一つを求め整数性を判定するプログラムです。参考にしてください。

  10 LET a=1
  20 LET b=3
  30 LET c=-4
  40 LET D=b^2-4*a*c  ! 判別式
  50 LET x=(-b+SQR(D))/(2*a)  ! 解の公式
  60 PRINT x
  70 IF INT(x)=x THEN PRINT "整数"
  80 END

*70行のIF文で整数の判定をしています。(IF文での等号は両辺が等しいかの判定に使われるので左辺が変数である必要はありません)
*INT(x)やSQR(D)は組込み関数です。(ヘルプ[数値][組込み関数][数値関数]参照)
*40行と50行の「!」は注釈記号です。この記号以降は何を書いてもプログラムの実行に影響を与えません。
 

Re: 質問です・・・

 投稿者:山中和義  投稿日:2008年11月13日(木)15時53分38秒
  > No.77[元記事へ]

NINAさんへのお返事です。

> 大学の数学の課題で、
>
> 「1,2,3,…,nの順に並んでいる数列のなかで、“+”と“=”を入れて式を完成させよ。」

データ列の処理として、もう1つ別解を紹介しておきます。


●「基本アルゴリズムの課題」としてのサンプル(その2)

方程式 n*(n+1)/2=2*k*(k+1)/2 より
2つの数列
 数列 S1={1,3,6,10,15,21,…,n*(n+1)/2,…}、n=1~1000000
 数列 S2={2,6,12,20,30,42,…,2*k*(k+1)/2,…}、k=1~1000000-1
を考える。
この2つの数列(データ列)は小さい順に整列されているので、
1つの整列されたデータ列に併合(マージ)することに着目する。
!OPTION ARITHMETIC decimal_high

LET t0=TIME

LET a=1000000

LET n=1 !先頭から
LET k=1

LET c=0 !個数
DO UNTIL n>a OR k>a-1 !どちらかのデータ列が終わるまで
   LET s1=n*(n+1)/2 !データ列を得る
   LET s2=2*k*(k+1)/2

   IF s1=s2 THEN !マージする
      LET c=c+1
      PRINT c;"個目"

      PRINT "1 + … +";k;"=";k+1; !左辺と=
      IF k<n-1 THEN !整形のため
         PRINT "+ … +";n; !右辺
      END IF
      PRINT "(=";s1/2;")" !和

      LET k=k+1
      LET n=n+1
   ELSEIF s1>s2 THEN
      LET k=k+1
   ELSE
      LET n=n+1
   END IF
LOOP

PRINT "計算時間=";TIME-t0

END

 

戻る