GAIさんへのお返事です。
> これを一般化して2n枚のカード
計算量 O(COMB(2*N,N)*FACT(N)) n=12は無理かな、、、
!問題
! 1~2nの数の記入されたカードで2枚ずつのペアをn組つくるとき、
! カードの数字の差がそれぞれ1、2、3、4、…、nになるような組み合わせを求めよ。
!答え
! n mod 4が0,1のとき、可能性がある。2,3なら、0
!
!n=1,2,3,4, 5,6,7, 8, 9,10,11,12,13,14,15, …
! 1,0,0,6,10,0,0,504,2656, 0, 0,??,??, 0, 0, …
!※パソコンの性能により調査できず
!PentiumⅢ700MHz,WindowsMe,2進モード n=9の場合、計算時間= 218.93 秒
LET t0=TIME
LET N=4 !1~2*Nの数が記入されたカード Ω={1,2,…,N-1,N,N+1,…,2*N-1,2*N}
LET s=1
FOR k=1 TO N !Σ[k=1,N]{COMB(2*k,2)/k}
LET s=s*COMB(2*k,2)/k
NEXT k
PRINT "場合の数=";s
LET ANSWER_COUNT=0
!●ステップ1
!ペアを適当に作って
! ペアの小さい方の数字P={a,b,c,d,…}の総和をA=a+b+c+d+ …
! ペアの大きい方の数字Q={x,y,z,w,…}の総和をB=x+y+z+w+ …
!とする。
LET w=0 !B+A=(a+b+c+d+ …)+(x+y+z+w+ …)=Σ[k=1,2*n]k …式[1]
FOR k=1 TO 2*N
LET w=w+k
NEXT k
LET s=0 !B-A=(a+b+c+d+ …)-(x+y+z+w+ …)=Σ[k=1,n]k …式[2]
FOR k=1 TO N
LET s=s+k
NEXT k
LET B=(w+s)/2 !連立方程式を解く [1]+[2]より
LET A=w-B ![1]に代入
PRINT "A=";A; "B=";B !debug
IF A<>INT(A) OR B<>INT(B) THEN
PRINT "AまたはBは整数でないので、解なし。"
STOP
END IF
!●ステップ2 Aに着目して、Pを求める。
DIM E(N) !初期パターン {1,2,3,4,…,N}
FOR k=1 TO N
LET E(k)=k
NEXT k
DIM P(N) !P={a,b,c,d,…}
MAT P=E
DO !ペアの全パターンから
LET s=0 !a+b+c+d+ …
FOR k=1 TO N
LET s=s+P(k)
NEXT k
IF P(1)<>1 THEN EXIT DO !※1∈P
IF P(N)<>2*N AND s=A THEN !条件を満たすもの ※2*N∈Q
MAT PRINT USING("P={"&REPEAT$("### ",N)&"}"): P !debug
!そのPからQは一意に求まる
DIM Q(2*N) !Q={x,y,z,w,…}=Ω-P
MAT Q=ZER !未使用とする
FOR k=1 TO N
LET Q(P(k))=-1 !使用とする
NEXT k
!!!FOR k=1 TO 2*N !Q
!!! IF Q(k)=0 THEN PRINT k;
!!!NEXT k
!!!PRINT
!●ステップ3 PとQが差の条件を満たすかどうか確認する
DIM R(N) !差分列 R={1,2,3,4,…}
MAT R=E
DO !Pと差分Rから機械的に、ペア (Pk,Pk+Rk)を生成する
DIM QQ(2*N)
MAT QQ=Q !restore it
FOR k=1 TO N !生成した数がQの要素(Pk+Rk∈Q)となるかどうか確認する
LET s=P(k)+R(k)
IF s>2*N THEN EXIT FOR !要素の範囲?
IF QQ(s)<>0 THEN EXIT FOR !一意性?
LET QQ(s)=k !使用とする
NEXT k
IF k>N THEN !Qと一致するなら、結果を表示する
LET ANSWER_COUNT=ANSWER_COUNT+1 !解答数
PRINT "No.";ANSWER_COUNT
FOR k=1 TO N !ペア (Pk,Pk+Rk)
PRINT "(";P(k);",";P(k)+R(k);") ";
NEXT k
MAT PRINT R; !差分列
ELSE
LET h=PermFactorial2Num(R,N) + FACT(N-k)-1 !…,Rk,~をスキップする
CALL Num2PermFactorial(h, R,N)
END IF
CALL NextPermFactorial(R,N, rc) !次へ
LOOP UNTIL rc=0 !FACT(N)通り
END IF
CALL NextComb(P,2*N,N, rc) !次へ
LOOP UNTIL rc=0 !COMB(2*N,N)通り
IF ANSWER_COUNT=0 THEN PRINT "解なし"
PRINT "計算時間=";TIME-t0
END
!異なるn個からr個を選ぶ組合せ COMB(N,R)通り
EXTERNAL SUB NextComb(A(),N,R, rc) !辞書式順序で次の組合せを返す
LET rc=0 !完了
FOR i=R TO 1 STEP -1
IF A(i)<N-R+i THEN !i~N-R+iで更新する
LET A(i)=A(i)+1
FOR j=i+1 TO R !A(i)<A(i+1)< … <A(R) 最初の並び
LET A(j)=A(j-1)+1
NEXT j
LET rc=1 !未了
EXIT SUB
END IF
NEXT i
END SUB
!異なるn個のものをすべて並べる FACT(n)通り
EXTERNAL FUNCTION PermFactorial2Num(A(),N) !順列パターンに番号を付ける ※辞書式順序
FOR j=1 TO N-1 !階乗進数の各桁の値+1 A[1..N]=(N-1)! … 3! 2! 1! 0!
FOR k=j+1 TO N
IF A(k)>=A(j) THEN LET A(k)=A(k)-1
NEXT k
NEXT j
LET v=0
FOR j=N TO 1 STEP -1 !非負の10進数整数へ
LET v=v*j+A(N-j+1)-1
NEXT j
LET PermFactorial2Num=v
END FUNCTION
EXTERNAL SUB Num2PermFactorial(h, A(),N) !番号から順列パターンを生成する ※辞書式順序
LET v=h !非負の10進数整数を階乗進数へ
FOR j=1 TO N
LET t=INT(v/j)
LET A(N-j+1)=v-t*j +1 !階乗進数の各桁の値+1 A[1..N]=(N-1)! … 3! 2! 1! 0!
LET v=t
NEXT j
FOR j=N-1 TO 1 STEP -1 !順列パターンへ
FOR k=j+1 TO N
IF A(k)>=A(j) THEN LET A(k)=A(k)+1
NEXT k
NEXT j
END SUB
EXTERNAL SUB NextPermFactorial(A(),N, rc) !辞書式順序で次の順列を返す
LET rc=0 !完了
LET i=N-1 !順列を右から左にみて、増加列から減少列に変わる位置iを探す
DO WHILE i>0 AND A(i)>=A(i+1) !0は番人
!!!DO WHILE i>0 AND A(i)<=A(i+1) !0は番人 ※前の順列 ←←←←←
LET i=i-1
LOOP
IF i=0 THEN EXIT SUB !A(1)>A(2)>A(3)> … >A(N)なら 例. N=4、4,3,2,1
LET j=N !その位置iより右で、A(i)以上で最小の数A(j)を探す
DO WHILE A(i)>=A(j)
!!!DO WHILE A(i)<=A(j) ! ※前の順列 ←←←←←
LET j=j-1
LOOP
LET t=A(i) !A(i)とA(j)を交換する
LET A(i)=A(j)
LET A(j)=t
LET i=i+1 !(i+1)からNまでの範囲を逆順にする
LET j=N
DO WHILE i<j
LET t=A(i) !swap it
LET A(i)=A(j)
LET A(j)=t
LET i=i+1
LET j=j-1
LOOP
LET rc=1 !未了
END SUB