Problem:

Problem C: Phone Number

Problem

株式会社ウクニキアの電話番、デンさんは毎日とても長い電話番号を電話に入力しています。

ある日余りにも疲れたデンさんは、疲れからか驚くべき考えに至りました。

「電話のボタンの配置を並べ替えたら少しでも楽できるのでは？！」

電話には$3 \times 3$で等間隔に区切られた正方形があり、9個のマスには並べ替えることのできる1から9までのボタンがそれぞれ1つずつついています。

電話番号を打つ際、デンさんは片手だけを使って、次の二つの操作を行うことができます。

 
人差し指を今触れているボタンに辺で隣接するいずれかのボタンに触れるように移動させる。

 
人差し指が触れているボタンを押す。

最初、人差し指は1から9までのいずれかのボタンに触れるように置くことができます。

デンさんは、最初のボタンを押してから最後のボタンを押し終わるまでの、人差し指の移動回数を最も小さくできる配置を効率的と考えています。

さて、ここに長さ$N$のお得意先の電話番号があります。

お得意先の電話番号だけ考えた時に、どのような配置が一番効率的でしょうか？

ボタンを並び替えることで、その配置を作ってください。

	

Input

入力は以下の形式で与えられる。

$N$
$S$

1行目にお得意先の電話番号の長さ$N$が与えられる。

2行目にお得意先の電話番号が1行に与えられる。

Constraints

入力は以下の条件を満たす。

  
$1 \leq N \leq 10^5 $

  
$S$は1から9までのいずれかの数字からなる文字列

Output

最も効率的な配置を、3行に空白を入れずに出力せよ。

但し、解答となり得る配置が複数ある場合は、左上の枠から

123

456

789

の順序で数字を並べた際に辞書順で最小となるようなものを出力せよ。

Sample Input 1

10
1236547896

Sample Output 1

123
456
789

Sample Input 2

11
31415926535

Sample Output 2

137
456
892



Sample input:
10
1236547896


Sample output:
123
456
789

Submission status: Accepted

Solution code:
def inpl(): return list(map(int, input().split()))
from collections import defaultdict
from itertools import combinations, permutations

N = int(input())
S = list(map(int, input()))

move = defaultdict(int)
b = S[0]
for i in range(N-1):
    a, b = S[i], S[i+1]
    move[(a, b)] += 1
    move[(b, a)] += 1

R = set(list(range(1, 10)))
bestscore = 10**10
bestans = "9"*9

def calc_br(bl, re):
    b0, b1, b2, b3 = bl
    r0, r1, r2, r3 = re
    stage3 = 0
    stage3 += move[(b0, r3)] + move[(b0, r0)] + 3*move[(b0, r1)] + 3*move[(b0, r2)]
    stage3 += move[(b1, r0)] + move[(b1, r1)] + 3*move[(b1, r2)] + 3*move[(b1, r3)]
    stage3 += move[(b2, r1)] + move[(b2, r2)] + 3*move[(b2, r3)] + 3*move[(b2, r0)]
    stage3 += move[(b3, r2)] + move[(b3, r3)] + 3*move[(b3, r0)] + 3*move[(b3, r1)]
    return stage3
    
    
def fliplr(black, bl, re):
    order = [bl[0], re[0], bl[1],
             re[3], black, re[1],
             bl[3], re[2], bl[2]]
    best = [9] * 9
    ixss = [[0, 1, 2, 3, 4, 5, 6, 7, 8],
            [2, 5, 8, 1, 4, 7, 0, 3, 6],
            [8, 7, 6, 5, 4, 3, 2, 1, 0],
            [6, 3, 0, 7, 4, 1, 8, 5, 2],
            [2, 1, 0, 5, 4, 3, 8, 7, 6],
            [0, 3, 6, 1, 4, 7, 2, 5, 8],
            [6, 7, 8, 3, 4, 5, 0, 1, 2],
            [8, 5, 2, 7, 4, 1, 6, 3, 0]]
    best = min(["".join([str(order[ix]) for ix in ixs]) for ixs in ixss])
    return best
    
    
for black in range(1, 10):
    remain = R.difference([black])
    for blue in combinations(remain, r=4):
        red = list(remain - set(blue))
        stage1 = 0
        for r in red:
            stage1 += move[(black, r)]
        for b in blue:
            stage1 += move[(black, b)] * 2
        for r1, r2 in combinations(red, 2):
            stage1 += move[(r1, r2)] * 2
    
        for bixs in [[0, 1, 2, 3], [0, 2, 3, 1], [0, 3, 1, 2]]:
            bl = [blue[bix] for bix in bixs]
            stage2 = (move[(bl[0], bl[1])] +
                      move[(bl[1], bl[2])] +
                      move[(bl[2], bl[3])] +
                      move[(bl[3], bl[0])] +
                      move[(bl[0], bl[2])]*2 +
                      move[(bl[1], bl[3])]*2)*2
            
            for re in permutations(red, 4):
                stage3 = calc_br(bl, re)
                score = stage1 + stage2 + stage3
                #if score == 11:
                #    print(black, bl, re)
                #print(stage1, stage2, stage3)
                if score <= bestscore:
                    if score < bestscore:
                        bestans = "9"*9
                    bestscore = score
                    bestans = min(bestans, fliplr(black, bl, re))
print("".join((map(str, bestans[:3]))))
print("".join((map(str, bestans[3:6]))))
print("".join((map(str, bestans[6:]))))