【問題1】     30個 【問題2】 +---+---+---+---+ | | | | + +---+---+ + | * | * | * | | +---+ + +---+ | * | * | * | | + +---+ + + | * | * | * | | +---+ +---+---+ (考え方)3x3の答え(*の部分)をもとに上側と右側の部分を拡張した 【問題3−1】   (答え) マッチ棒の数をL(n)とすると       L(n)=2*n*(n+1) (求め方)       L(1)= 4      δL(n)= L(n)−L(n−1)とすると、δL(n)=4*nとなる。      これより、L(n)=ΣδL(k)として、上記の答えを得る。      ex.L(4)=2*4*(4+1)=40 【問題3−2】   (答え) 正方形の個数をS(n)とすると       S(n)=n*(n+1)*(2*n+1)/6 (求め方)       mxmの正方形は、横方向に(n−m+1)個、縦方向にも(n−m+1)個を配置できるので       全体では、(n−m+1)**2個が存在する。従って、         S(n)=n**2 + (nー1)**2 + (nー2)**2 +...+ 1**2           =Σk**2= Σ{k*(k−1)+k}           =n*(n+1)(n−1)/3+n*(n+1)/2           =n*(n+1)*(2*n+1)/6 【おまけ1】   (答え) 以下の2個。ただし、対称解を別物として数える場合は、16個。      ==== 1 / 8 ==== +---+ +---+---+ | | | | | + +---+ + + | | | | | +---+ + +---+ | | | | | + +---+---+ + | | | | +---+---+---+---+ ==== 2 / 16 ==== +---+ +---+---+ | | | | + +---+---+---+ | | | | +---+---+---+ + | | | +---+---+---+---+ | | | +---+---+---+---+ 【問題2】の解は、最初の解を上下反転したものに一致している。 n=5の場合は、91個。ただし、対称解を別物として数える場合は、720個。   (求め方) プログラム(最後に添付)による探索で求めた。(プログラムの説明は割愛)     【おまけ2】     (答え) 取り除くマッチ棒の最小数をm(n)とすると        m(n)=[(n**2+1)/2]+1        ただし、[a]はガウス記号で、aの整数部分を表す。(ex.[3]=3,[3.5]=3)        n  m(n)       ----------------        3   6         4   9        5  14        6  19        7  26    (求め方)     n=3は、明らか(『正方形の消滅』参照)であるので、n>=4について調べることにする。     1)取り除くマッチ棒の数がm(n)となるような解が存在することを以下に示す。       n=4は、【問題2】で明らかである。       n>4については、4x4の解をベースとして以下の手順で作ることができる。       nが偶数のとき、nxnから(n+1)x(n+1)の解を作る手順         a)nxnの上側に左から右へと1x2の長方形を並べる         b)nxnの右側に上から下へと2x1の長方形を並べる            c)右下の1x1の正方形の領域は、下の部分を開けたままにする       nが奇数のとき、nxnから(n+1)x(n+1)の解を作る手順         d)nxnの左側に上から下へと2x1の長方形を並べる。         e)nxnの下側にある1x1の正方形(下が開いている)は、2x1の長方形にする            f)e)で作られた長方形ではさまれた部分を1x2の長方形でうめる         g)d),e)にはさまれた1x1の正方形の領域は、下の部分を開けたままにする       上記の手順a)〜g)により、n=4から順にn=5〜8を作成する例を示す。        +--+--+ | a |は、手順a)の操作で作られたことを表す。(b〜gも同様) +--+--+    n=4の場合(ベース解)  +---+---+---+---+ | | | | + +---+---+ + | | | | | +---+ + +---+ | | | | | + +---+ + + | | | | | +---+ +---+---+ n=5の場合   +---+---+---+---+---+ | a | a | | +---+---+---+---+ b + | | | | | + +---+---+ +---+ | | | | | | +---+ + +---+ b + | | | | | | + +---+ + +---+ | | | | | c | +---+ +---+---+ +   n=6の場合 +---+---+---+---+---+---+ | | | | | + d +---+---+---+---+ + | | | | | | +---+ +---+---+ +---+ | | | | | | | + d +---+ + +---+ + | | | | | | | +---+ +---+ + +---+ | | | | | | | + d +---+ +---+---+ + | | g | e | f | e | +---+ +---+---+---+---+   n=7の場合 +---+---+---+---+---+---+---+ | a | a | a | | +---+---+---+---+---+---+ b + | | | | | | + +---+---+---+---+ +---+ | | | | | | | +---+ +---+---+ +---+ b + | | | | | | | | + +---+ + +---+ +---+ | | | | | | | | +---+ +---+ + +---+ b + | | | | | | | | + +---+ +---+---+ +---+ | | | | | | c | +---+ +---+---+---+---+ +   n=8の場合 +---+---+---+---+---+---+---+---+ | | | | | | + d +---+---+---+---+---+---+ + | | | | | | | +---+ +---+---+---+---+ +---+ | | | | | | | | + d +---+ +---+---+ +---+ + | | | | | | | | | +---+ +---+ + +---+ +---+ | | | | | | | | | + d +---+ +---+ + +---+ + | | | | | | | | | +---+ +---+ +---+---+ +---+ | | | | | | | | + d +---+ +---+---+---+---+ + | | g | e | f | f | e | +---+ +---+---+---+---+---+---+     2)解が存在するための,必要条件       l(n)を以下のように定義すると、解が存在するためには、取り除くマッチ棒の数>=l(n)を       満たすことが必要である。         l(n)=[n**2/2]+1              ただし、[k]はガウス記号で、kの整数部分を表す。         1x1の正方形はn**2個存在する。この正方形をもっとも少ない数のマッチ棒で消滅させるには、       2つの1x1の正方形の間の1本を取り除いて、1x2 or 2x1の長方形を作ることである。       n**2個の正方形をこの方法で行うとすると、[n**2/2]本のマッチ棒が必要である。       (ただし、nが奇数の場合は、1x1の正方形が1つ余る)一方、この方法では、nxnの正方形は       消滅しないので、これを消滅させるために、もう1本のマッチ棒が必要となる。       従って、[n**2/2]+1=l(n)が必要である。       nが奇数の場合、1x1の正方形が1つ残るが、この正方形は、nxnの正方形と辺を共有してい       れば、nxnの正方形を消滅させる時に、同時に消滅させることができる。       従って、nが奇数の場合も、[n**2/2]+1=l(n)本のマッチ棒が必要条件となる。     3)次に、m(n)が最小解であることを示す        nが偶数の場合、[(n**2+1)/2]=[n**2/2]となり、m(n)=l(n)が成立       するので、m(n)は最小解である。       nが奇数の場合、m(n)=l(n)+1が成り立つ。もし、l(n)となる解が存在しなければ、       m(n)が最小解といえる。 補題1 下図のように、1x2の長方形Aの両側をガードされた状態で、x,yの位置を1x2と           2x1の長方形だけで埋めることはできない。  +---+ +---+ | | x y| | G1,G2は、2x1の長方形又は端 + G1+---+---+ G2+ | | A | | +---+---+---+---+           ∵ x、yを埋めようとすると、どうしても2x2の正方形ができてしまう。 補題2 下図のように、1x2の長方形がk個並んだ両側をガードされた状態で、x1...x2k           の位置を1x2と2x1の長方形だけで埋める場合、1x2の長方形は、高々(k−1)個           しか並べることができない。   +---+ +---+ | | x1 x2 ... x2k| | G1,G2は、2x1の長方形又は端 + G1+---+---+---+---+---+---+ G2+ | | A1 | ... | Ak | | +---+---+---+---+---+---+---+---+           x1,x2kの位置は、2x1の長方形を配置しなければならないので、残りを1x2の長方           形で埋めたとしても高々(k−1)個となる。         補題1,2を使って、l(n)となる解が存在しないことを示す。       もし、l(n)の解が存在すると仮定すると、1x1の正方形がnxnの正方形と辺を共有し、その       辺は取り除かれている。残りの(n**2−1)個の1x1の正方形は、2つが合わさって1x2 or       2x1の長方形となっていなければならない。(l(n)の項で述べたこと) +---+ +---+---+---+ | | A | | ←-n段 + +---+ + | | + + | 1x2 or 2x1 | ←-3段 + の長方形で埋める + | | ←-2段 + + | | ←-1段 +---+---+---+---+---+ 上図のように、1段、2段、...、n段と順に1x2or2x1の長方形を埋めていくことにする。       なお、1x1の正方形Aは最上段に配置することにする。(こうしても一般性は失われない)       nは奇数なので、n=(2*k+1)とすると、1段目には最大でk個の1x2の長方形を配置する       ことができる。1段目にk個を配置した場合、補題2により、2段目は、高々(k−1)個の1x2       の長方形しか配置できない。これを繰り返していくと、k段目で補題1の状態となり、これ以上は配       置できなくなる。(即ち、解が存在しない)もし、途中で、1x2の長方形の数を少なく配置した場       合は、もっと少ない段数で補題1の状態となる。       例 5x5の場合 +---+ +---+---+---+ +---+ +---+---+---+ +---+ +---+---+---+ | | A | | | | A | | | | A | | + +---+ + + +---+ + + +---+ + | | | | | | + + --> + + --> + +---+ +---+ -->解なし | | | | | | | x y | |  (補題1) + + +---+ + +---+ +---+---+ +  | | | | | | | | | | + + + +---+---+---+---+ + +---+---+---+---+ | | | | | | | | | | +---+---+---+---+---+ +---+---+---+---+---+ +---+---+---+---+---+       (1)初期状態       (2)1段目を埋めた状態  (3)2段目を埋めた状態        以上より、1x2の長方形は、高々k段までした積み上げることができないので、解は存在しない。       従って、nが奇数の場合、l(n)となる解は存在しないので、m(n)が最小解である。    <<おまけ2のサマリ>>     少し長くなったので、以上の論旨をまとめると      1)取り除くマッチ棒の数がm(n)となるような解が存在する。      2)解が存在するためには、取り除くマッチ棒の数>=l(n)を満たすことが必要である。      3)nが偶数の場合、m(n)=l(n)が成立するので、m(n)は最小解である。       nが奇数の場合、m(n)=l(n)+1が成り立つ。しかし、l(n)となる解が存在しない ことが示されたので、m(n)が最小解となる。 --------- 【おまけ1】の探索プログラム ----------------------------------------------------------- ##### 20004.06.06 # # import time def exe(N) : global AnsCount,DupCount,out out = open("s%d-log.txt" % N,"w") Init(N) L = 2 * N * (N+1) S = [0] for m in range(1,N+1) : mask = 0L for k in range(0,L) : mask |= M[m][k] S += [mask] AnsCount = 0 DupCount = 0 maxdepth = (N*N + 1) / 2 + 1 OuterSearch(maxdepth,0,-1,[],S,N) out.close() ## def OuterSearch(MaxDepth,nest,Pos,PosList,S,N) : if nest == 0 : for p in range(0,(N+1)/2) : Line = ("\n=== Search pos:%d Started === : " % (p)) + time.ctime() WriteLog(out,Line) SS = [0] for m in range(1,N+1) : SS += [ (S[m] | M[m][p]) ^ M[m][p] ] InnerSearch(MaxDepth,nest+1,-1,[p],SS,N) OuterSearch(MaxDepth,nest+1,p,[p],SS,N) Line = "\n=== Search Ended === : " + time.ctime() WriteLog(out,Line) return if MaxDepth < ((N*N - nest) / 2 + nest + 1) : return for pi in range(Pos+1,len(OutPos)) : p = OutPos[pi] poslist = PosList + [p] if DupCheck(poslist,N) < 0 : continue SS = [0] for m in range(1,N+1) : SS += [ (S[m] | M[m][p]) ^ M[m][p] ] InnerSearch(MaxDepth,nest+1,-1,poslist,SS,N) OuterSearch(MaxDepth,nest+1,pi,poslist,SS,N) ## def InnerSearch(MaxDepth,nest,Pos,PosList,S,N) : global AnsCount,DupCount if nest == MaxDepth : for m in range(1,N+1) : if S[m] != 0 : return cnt = DupCheck(PosList,N) if cnt < 0 : return AnsCount += 1 DupCount += cnt ID = "\n ==== %d / %d ====" % (AnsCount,DupCount) printFig(ID,PosList,N) return for pi in range(Pos+1,len(InPos)) : p = InPos[pi] poslist = PosList + [p] SS = [0] for m in range(1,N+1) : SS += [ (S[m] | M[m][p]) ^ M[m][p] ] if (bitcount(SS[1])+1)/2 + nest >= MaxDepth : continue InnerSearch(MaxDepth,nest+1,pi,poslist,SS,N) ## def bitcount(Mask) : w = Mask c = 0 while w != 0 : c += 1 w = w & (w-1) return c ## def DupCheck(PosList,N) : NN = N * (N+1) C = [] for t in range(0,8) : Pmask = 0L for p in PosList : if p < NN : i = p % N ; j = p / N if t & 0x01 : i = N-1 - i if t & 0x02 : j = N - j q = i + j*N if t & 0x04 : q += NN else : i = (p-NN) % N ; j = (p-NN) / N if t & 0x02 : i = N-1 - i if t & 0x01 : j = N - j q = i + j*N + NN if t & 0x04 : q -= NN Pmask |= 1L << (NN+NN-q) if t == 0 : P = Pmask C =[P] else : if (P & OutMask) < (Pmask & OutMask) : return -1 if (P & OutMask) == (Pmask & OutMask) : if (P & InMask) < (Pmask & InMask) : return -1 if Pmask not in C : C += [Pmask] return len(C) ## def Init(N) : global M,InPos,OutPos,InMask,OutMask NN = N * (N+1) M = [[]] for m in range(1,N+1) : mask = [] for k in range(0,2*NN) : mask += [0] M += [mask] for i in range(0,N) : if i+m > N : break for j in range(0,N) : if j+m > N : break p = i*N + j q = p + m*N r = i + NN + j*N s = r + m*N for k in range(0,m) : a = p + k b = q + k c = r + k d = s + k M[m][a] |= 1L << p M[m][b] |= 1L << p M[m][c] |= 1L << p M[m][d] |= 1L << p Line= " m=%d p=%d (%d,%d,%d,%d)" % (m,p,a,b,c,d) WriteLog(out,Line) InPos = [] ; InMask = 0L OutPos = [] ; OutMask = 0L NN2 = 2 * NN for p in range(0,NN2) : if p < NN : i = p / N else : i = (p-NN) / N if (i == 0) | (i == N) : OutPos += [p] ; OutMask |= 1L << (NN2-p) else : InPos += [p] ; InMask |= 1L << (NN2-p) ## def printFig(ID,PosList,N) : H = [] ; V = [] h = '+'; v = '|' for k in range(0,N) : h += '---+' v += ' |' for n in range(0,N+1) : H += [h] V += [v] for p in PosList : if p < N*(N+1) : i = p % N j = p / N h = H[j] h = h[:i*4+1] + ' ' + h[i*4+4:] H[j] = h else : p = p - N*(N+1) i = p % N j = p / N v = V[i] v = v[:j*4] + ' ' + v[j*4+3:] V[i] = v WriteLog(out,ID) for k in range(0,2*N+1): if (k & 0x01) : WriteLog(out,' ' + V[k/2]) else : WriteLog(out,' ' + H[k/2]) ### def WriteLog(out,Line) : print Line out.write(Line+"\n") out.flush() ----------------------------------------------------------------------------------------