Official

D - Shift Puzzle Editorial by toam


\(S\)\(T\) に含まれる # の個数が等しくない場合明らかに不可能です.逆に # の個数が等しい場合は必ず \(N^3\) 手以内で一致させることが可能です.

以下,# の個数が等しい場合の操作手順について述べます.

\((S_{x,y},T_{x,y})=\) \((\) # \(,\) . \()\) となる \((x,y)\) の個数と, \((S_{x,y},T_{x,y})=\) \((\) . \(,\) # \()\) となる \((x,y)\) の個数は等しいです.ここで, \((S_{x_1,y_1},T_{x_1,y_1})=\) \((\) # \(, \) . \()\)\((S_{x_2,y_2},T_{x_2,y_2})=\) \((\) . \(,\) # \()\) を満たす \((x_1,y_1),(x_2,y_2)\) を任意に選んだとき, \(2N\) 手の操作によって \((x_1,y_1),(x_2,y_2)\)\(2\) 点 swap ( \(S_{x_1,y_1}\) = . \(,S_{x_2,y_2}\) = # にする)を行うことができます. \((S_{x,y},T_{x,y})=\) \((\) # \(,\) . \()\) となる \((x,y)\) の個数は高々 \(N^2/2\) 個ですから,全体で \(2N\times N^2/2=N^3\) 手以内で \(S\)\(T\) に一致させることができます.

2 点 swap の方法

下図左上にあるような配置にある \(3\) つのマス \(X,Y,Z\)\(X,Y\) は同じ行に, \(Y,Z\) は同じ列にある)に対して, \(2N\) 手の操作によって \((X,Y,Z)\)\((Y,Z,X)\)\((Z,X,Y)\) に同時に rotate することができます.(図では \((X,Y,Z)\)\((Z,X,Y)\) に置き換える場合を示しています.)

ここで色の種類が \(2\) 種類しかないことを踏まえると, \(3\) つのマスの rotate を利用することで色の \(2\) 点 swap を実現することが可能です.

\(X,Z\) の色を swap する場合

\(Y\) のマスの色が \(X\) のマスの色と等しいか \(Z\) のマスの色と等しいかで場合分けします.

\(X,Y\) の色を swap する場合

\(Z\) のマスの色が \(X\) のマスの色と等しいか \(Y\) のマスの色と等しいかで場合分けします.

実装例 (Python)

def op(t, x, c):
    for _ in range(c):
        print(t + 1, x + 1)

def swap(x0, y0, x1, y1, f):
    # X: (x0, y0), Y: (x0, y1), Z: (x1, y1)
    if f:
        # X -> Z, Z -> Y, Y -> X
        op(0, x0, (y1 - y0) % n)
        op(1, y1, (x0 - x1) % n)
        op(0, x0, (y0 - y1) % n)
        op(1, y1, (x1 - x0) % n)
    else:
        # X -> Y, Y -> Z, Z -> X
        op(1, y1, (x0 - x1) % n)
        op(0, x0, (y1 - y0) % n)
        op(1, y1, (x1 - x0) % n)
        op(0, x0, (y0 - y1) % n)

n = int(input())
S = [list(input()) for i in range(n)]
T = [list(input()) for i in range(n)]

S0, T0 = [], []
for x in range(n):
    for y in range(n):
        if S[x][y] == T[x][y]:
            continue
        if S[x][y] == ".":
            S0.append((x, y))
        if T[x][y] == ".":
            T0.append((x, y))

if len(S0) != len(T0):
    print("No")
    exit()

print("Yes")
print(len(S0) * 2 * n)
for i in range(len(S0)):
    x0, y0 = S0[i]
    x1, y1 = T0[i]
    if x0 != x1 and y0 != y1:
        swap(x0, y0, x1, y1, S[x0][y1] == ".")
    elif x0 == x1:
        x2 = (x0 + 1) % n
        swap(x0, y0, x2, y1, S[x0][y1] == S[x2][y1])
    else:
        y2 = (y1 + 1) % n
        swap(x0, y2, x1, y1, S[x0][y2] == S[x1][y1])
    S[x0][y0], S[x1][y1] = S[x1][y1], S[x0][y0]

posted:
last update: