助けて下さい。

 投稿日:2008年11月16日(日)20時54分54秒
  早速リストをコピーして動かしてみたら、OKでした。
k=5 でやっていますが、朝から動かしていますがまだ終わりません。(12時間近く。)
せめて、1時間位で調査できないものでしょうか?
どこをどう改良したらよいのか・・・、誰か助け舟が欲しい!!!
 

Re: 助けて下さい。

 投稿者:荒田浩二  投稿日:2008年11月16日(日)22時07分56秒
  > No.86[元記事へ]

GAIさんへのお返事です。


ごめんなさい。
あれは20分くらいで取り合えず作ったもので、作りながらも「無駄が多い」と考えてはいました。
ランダム調査で試行回数がCEIL(k/2)*SQR(n^n)ですから、n=15ではなかなか終わらないと思います。

さっそく改良版を作ります。
明日までにはできるかと思います。
 

Re: 助けて下さい。

 投稿者:荒田浩二  投稿日:2008年11月17日(月)23時52分29秒
  > No.86[元記事へ]

GAIさんへのお返事です。


全数調査用プログラム完成しました。

まず1行目を決めて、差を取っていき数字の重複がないか調査します。

k行でn個の数字とすると、(n-1)個から(k-1)個を取り出した順列pの前半部分にnを挿入して1行目を構成します。

調査回数を減らすために、対称的な数列はキャンセルするようにしました。

たとえば、k=5,n=15で配列pが 7,11,6,9 だとします。

調査するのは、

  15,7,11,6,9
  7,15,11,6,9
  7,11,15,6,9

この3通りとします。

7,11,6,15,9 と 7,11,6,9,15 は、配列pが 9,6,11,7 のときに調査します。

また、このときは 9,6,15,11,7 は調査しません。


  行数     実行時間   調査回数     解
  k=2 --->   0.03 秒         2 回   2個
  k=3 --->   0.08 秒        30 回   4個
  k=4 --->   0.14 秒      1008 回   4個
  k=5 --->   2.05 秒     60060 回   1個
  k=6 ---> 192.16 秒   5581440 回   0個 (2進モードで100.20秒)
  k=7 ---> 未調査    745945200 回   ?個 (2進モードでも4時間近くか?)
  k=8 ---> 未調査 135566323200 回   ?個


DECLARE EXTERNAL SUB combi
PUBLIC NUMERIC k,n,h,pt,count
LET t0=TIME
LET k=5         ! 行数
LET n=k*(k+1)/2 ! 最大値
LET h=INT(k/2)  ! 半分
LET pt=MOD(k,2) ! 奇偶
DIM nn(n-1),c(k-1)
MAT nn=ZER
LET count=0
LET j=0
CALL combi(nn,1,k-1,j,c)
PRINT TIME-t0;"秒",count;"回"
END

EXTERNAL SUB differ(p()) !注意:一部改良しました
DIM a(k,k),ck(n-1)
LET a(1,1)=n
FOR j=2 TO k
   LET a(1,j)=p(j-1)
NEXT j
CALL check
FOR j=2 TO h
   SWAP a(1,j-1),a(1,j)
   CALL check
NEXT j
IF pt=1 AND p(1)<p(k-1) THEN ! nが中央のとき
   SWAP a(1,h),a(1,h+1)
   CALL check
END IF
SUB check
   LET count=count+1
   MAT ck=ZER
   FOR r=1 TO k-1
      LET ck(p(r))=1
   NEXT r
   FOR ii=1 TO k-1
      FOR jj=1 TO k-ii
         LET d=ABS(a(ii,jj)-a(ii,jj+1))
         IF ck(d)=1 THEN EXIT SUB ! 数値重複
         LET ck(d)=1
         LET a(ii+1,jj)=d
      NEXT jj
   NEXT ii
   MAT PRINT a;  ! 解あり
END SUB
END SUB

REM 十進BASIC添付"\BASICw32\SAMPLE\COMBINAT.BAS"より
REM 1~n-1の集合からr個を選ぶ組合せを生成する。
EXTERNAL SUB combi(nn(),kk,r,j,c())
DECLARE EXTERNAL SUB permu
! kk以降の数からr個を選択する
IF r=0 THEN
   FOR i=1 TO n-1
      IF nn(i)=1 THEN
         LET j=j+1
         LET c(j)=i
      END IF
   NEXT i
   !MAT PRINT c;
   CALL permu(c,1)
   LET j=0
ELSE
   FOR i=kk TO n-r
      LET nn(i)=1
      CALL combi(nn,i+1,r-1,j,c)
      LET nn(i)=0
   NEXT i
END IF
END SUB

REM 十進BASIC添付"\BASICw32\SAMPLE\PERMUTAT.BAS"より
REM (k-1)個の数値の順列を辞書式順序で生成する。
EXTERNAL SUB permu(p(),r)
DECLARE EXTERNAL SUB differ
IF r=k-1 THEN
!MAT PRINT p;
   CALL differ(p)
ELSE
   FOR i=r TO k-1
      LET t=p(i)
      FOR j=i-1 TO r STEP -1
         LET p(j+1)=p(j)
      NEXT j
      LET p(r)=t
      CALL permu(p,r+1)
      LET t=p(r)
      FOR j=r TO i-1
         LET p(j)=p(j+1)
      NEXT j
      LET p(i)=t
   NEXT i
END IF
END SUB
 

Re: 助けて下さい。

 投稿日:2008年11月18日(火)10時38分17秒
  > No.91[元記事へ]

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

>
>   行数     実行時間   調査回数     解
>   k=2 --->   0.03 秒         2 回   2個
>   k=3 --->   0.08 秒        30 回   4個
>   k=4 --->   0.14 秒      1008 回   4個
>   k=5 --->   2.05 秒     60060 回   1個
>   k=6 ---> 192.16 秒   5581440 回   0個 (2進モードで100.20秒)
>   k=7 ---> 未調査    745945200 回   ?個 (2進モードでも4時間近くか?)
>   k=8 ---> 未調査 135566323200 回   ?個

前回k=5で丸一日でも計算途中と終了せずになっていたものが、
今回のプログラムで4.28秒(なんという短時間)で結果が出てきました。
6万回以上のチェックがこんな短時間になされているなんて、おいらの頭はなんなんだ!
プログラム一つでこうも違うことになるとは、プログラムの世界も奥深いですね。
 

Re: 助けて下さい。

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

GAIさんへのお返事です。

> プログラム一つでこうも違うことになるとは、プログラムの世界も奥深いですね。


今回紹介されたプログラムは以下の手法を用いています。

・モンテカルロ法
 ランダムに数字を埋めて条件に合うか確認する。
 確率ですから、「偶然にみつかる」を期待する。
 →荒田浩二さんの1回目

・バックトラック法
 順列や組合せによる数字を発生して、条件に合うように順に数字を埋めていく。(今回は下から)
 枝刈り効果(矛盾発生以降は対象外とする処理)を期待する。(検証回数が減る)
 →私の1回目

・「場合の数」法
 問題に応じた「場合の数」を、順列や組合せを考えて最小回数の検証を行う。
 →荒田浩二さんの2回目
 →私の2回目


プログラミングは、コーディング(言語による表現)より、
アルゴリズム(解き方)を検討するのが主だと思います。
 

戻る