Submission #74064809


Source Code Expand

import bisect, heapq, sys, math, copy, itertools, decimal
from collections import defaultdict, deque
import pprint
from typing import Iterable, List, Tuple
import numpy as np
sys.setrecursionlimit(10**7)
def INT(): return int(input())
def MI(d=0): return map(lambda x:int(x)+d, input().split())
def MS(): return map(str, input().split())
def LI(d=0): return list(map(lambda x:int(x)+d, input().split()))
def LS(): return list(map(str, input().split()))
def pr_line(itr): print(*itr, sep='\n')
def pr_mtx(matrix): [print(*row) for row in matrix] 
def pr_mtx2(matrix, l=2):
    for row in matrix:
        for x in row:
            print(str(x).rjust(l), end='')
        print('\n')
def pr_stderr(*s): print(*s, file=sys.stderr)

dij = [[1, 0], [0, 1], [-1, 0], [0, -1]]
dij2 = [[1, 0], [0, 1], [-1, 0], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]]
INF = float('inf')


from time import time
base_ms = 0
def tic():
    global base_ms
    base_ms = time()

def toc():
    now = time()
    return (now - base_ms) * 1000
###########################################################
# input
N = INT()
A = [LI() for _ in range(N)]
###########################################################
Coord = Tuple[int, int]
###########################################################
def score(tour: Iterable[Tuple[int, int]]) -> int:
    s = 0
    for i, (r, c) in enumerate(tour):
        s += A[r][c] * (i + 1)
    return s


def cheb_adj(a: Coord, b: Coord) -> bool:
    return max(abs(a[0] - b[0]), abs(a[1] - b[1])) == 1

def snake_coords(h: int, w: int) -> List[Coord]:
    """h×w を行ごと往復で走査する座標, ローカル"""
    res = []
    for r in range(h):
        if r % 2 == 0:
            for c in range(w):
                res.append((r, c))
        else:
            for c in range(w - 1, -1, -1):
                res.append((r, c))
    return res

def two_row_bundle_path(n: int, t: int) -> List[Coord]:
    """
    2行ずつ束ねて走査するハミルトン路を返す。
    出力は(0-index)。
    """
    assert n % 2 == 0
    path: List[Coord] = []
    visited = [[False] * n for _ in range(n)]
    for r in range(0, n, 2):
        si, sj = transform_point((r, 0), n, n, t)
        path.append((si, sj))
        visited[si][sj] = True

        for c in range(1, n):
            i1, j1 = transform_point((r, c), n, n, t)
            i2, j2 = transform_point((r+1, c), n, n, t)
            if A[i1][j1] < A[i2][j2]:
                path.append((i1, j1))
                visited[i1][j1] = True
            else:
                path.append((i2, j2))
                visited[i2][j2] = True

        for c in range(n - 1, -1, -1):
            i1, j1 = transform_point((r, c), n, n, t)
            i2, j2 = transform_point((r+1, c), n, n, t)
            if not visited[i1][j1]:
                path.append((i1, j1)) 
                visited[i1][j1] = True
            if not visited[i2][j2]:
                path.append((i2, j2))
                visited[i2][j2] = True

    return path

def transform_point(rc: Coord, h: int, w: int, t: int) -> Coord:
    """
    h×w のグリッド上の1点 (r,c) を 8通り (D4) で変換する。
    t in [0..7]
      0: identity
      1: rot90
      2: rot180
      3: rot270
      4: flipH (左右反転)
      5: flipH + rot90
      6: flipH + rot180
      7: flipH + rot270
    """
    r, c = rc
    rr, cc = r, c

    if t >= 4:
        cc = (w - 1) - cc  # horizontal flip

    k = t % 4
    if k == 0:
        return (rr, cc)
    elif k == 1:
        # (r,c) in h×w -> (c, h-1-r) in w×h
        return (cc, (h - 1) - rr)
    elif k == 2:
        return ((h - 1) - rr, (w - 1) - cc)
    else:  # k == 3
        return ((w - 1) - cc, rr)

def block_order(nb_r: int, nb_c: int) -> List[Coord]:
    """ブロック座標(Br,Bc)を牛耕式で並べる"""
    order = []
    for br in range(0, nb_r, 2):
        for bc in range(nb_c):
            order.append((br, bc))
        for bc in range(nb_c - 1, -1, -1):
            order.append((br + 1, bc))
    return order

def eval_block_local_score(local_path: List[Coord], A: List[List[int]], base_i: int, base_j: int, k0: int) -> int:
    """
    ブロック内だけの寄与を評価(絶対kを使う)。
    local_path はブロック内ローカル座標列。
    """
    s = 0
    for dk, (r, c) in enumerate(local_path):
        s += (k0 + dk) * A[base_i + r][base_j + c]
    return s

def main() -> List[Coord]:

    B = 10  # ブロックサイズ(要調整)
    assert N % B == 0
    nb_r = N // B
    nb_c = N // B

    base_local = snake_coords(B, B)  # B×B の基本牛耕

    order = block_order(nb_r, nb_c)

    path: List[Coord] = []
    prev: Coord | None = None
    k = 0


    # for idx, (br, bc) in enumerate(order):
    #     bi = br * B
    #     bj = bc * B

    #     best_local = None
    #     best_score = None

    #     # 8通りの向きを試す
    #     for t in range(8):
    #         local = transform(base_local, B, B, t)

    #         first_abs = (bi + local[0][0], bj + local[0][1])
    #         if prev is not None and not cheb_adj(prev, first_abs):
    #             continue  # 入り口が繋がらない

    #         sc = eval_block_local_score(local, A, bi, bj, k)

    #         if best_score is None or sc > best_score:
    #             best_score = sc
    #             best_local = local

    #     # どれも繋がらない場合は、保険で「前ブロックの最後と隣接するマス」を先頭にするよう調整が要るが、
    #     # B×B正方形&ブロック牛耕なら通常は繋がる向きが見つかるはず。
    #     if best_local is None:
    #         # フォールバック:繋がり無視でそのまま(最悪不正になるので、本来はここを潰すべき)
    #         best_local = base_local

    #     # 追加
    #     for (r, c) in best_local:
    #         path.append((bi + r, bj + c))
    #     prev = path[-1]
    #     k += B * B

    # 念のため、逆順も比較(開始終了自由なので逆順も合法)
    def total_score(p: List[Coord]) -> int:
        s = 0
        for kk, (i, j) in enumerate(p):
            s += kk * A[i][j]
        return s

    p_rev = list(reversed(path))
    if total_score(p_rev) > total_score(path):
        path = p_rev
    return path


def is_valid_path(n: int, path: List[Coord]) -> bool:
    if len(path) != n * n:
        return False
    used = set(path)
    if len(used) != n * n:
        return False
    for (i, j) in path:
        if not (0 <= i < n and 0 <= j < n):
            return False
    for k in range(n * n - 1):
        a, b = path[k], path[k + 1]
        if max(abs(a[0] - b[0]), abs(a[1] - b[1])) != 1:
            return False
    return True
###########################################################
def solve():
    path = [(i, j) for i in range(N) for j in range(N)]
    mx_score = score(path)
    for t in range(8):
        tmp_path = two_row_bundle_path(N, t)
        tmp_score = score(tmp_path)
        if tmp_score > mx_score and is_valid_path(N, tmp_path):
            path = tmp_path
            mx_score = tmp_score
    for r, c in path:
        print(r, c)
###########################################################
if __name__ == '__main__':
    solve()

Submission Info

Submission Time
Task A - King's Tour
User BenKenobi
Language Python (PyPy 3.11-v7.3.20)
Score 40142080933
Code Size 7523 Byte
Status AC
Exec Time 730 ms
Memory 176812 KiB

Judge Result

Set Name test_ALL
Score / Max Score 40142080933 / 100000000000
Status
AC × 100
Set Name Test Cases
test_ALL test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt
Case Name Status Exec Time Memory
test_0000.txt AC 722 ms 176068 KiB
test_0001.txt AC 717 ms 173440 KiB
test_0002.txt AC 715 ms 171792 KiB
test_0003.txt AC 716 ms 175016 KiB
test_0004.txt AC 713 ms 171592 KiB
test_0005.txt AC 714 ms 172056 KiB
test_0006.txt AC 717 ms 172056 KiB
test_0007.txt AC 716 ms 171292 KiB
test_0008.txt AC 717 ms 171716 KiB
test_0009.txt AC 726 ms 173448 KiB
test_0010.txt AC 730 ms 175988 KiB
test_0011.txt AC 727 ms 174876 KiB
test_0012.txt AC 723 ms 172836 KiB
test_0013.txt AC 723 ms 175276 KiB
test_0014.txt AC 717 ms 167664 KiB
test_0015.txt AC 717 ms 172304 KiB
test_0016.txt AC 720 ms 171168 KiB
test_0017.txt AC 726 ms 175664 KiB
test_0018.txt AC 719 ms 171944 KiB
test_0019.txt AC 721 ms 172992 KiB
test_0020.txt AC 710 ms 167992 KiB
test_0021.txt AC 721 ms 173356 KiB
test_0022.txt AC 723 ms 176164 KiB
test_0023.txt AC 719 ms 172768 KiB
test_0024.txt AC 715 ms 173132 KiB
test_0025.txt AC 719 ms 173092 KiB
test_0026.txt AC 719 ms 175044 KiB
test_0027.txt AC 718 ms 171932 KiB
test_0028.txt AC 723 ms 174700 KiB
test_0029.txt AC 720 ms 176640 KiB
test_0030.txt AC 709 ms 167748 KiB
test_0031.txt AC 721 ms 174568 KiB
test_0032.txt AC 716 ms 171556 KiB
test_0033.txt AC 718 ms 170916 KiB
test_0034.txt AC 716 ms 172960 KiB
test_0035.txt AC 723 ms 175244 KiB
test_0036.txt AC 718 ms 171560 KiB
test_0037.txt AC 713 ms 167952 KiB
test_0038.txt AC 714 ms 171532 KiB
test_0039.txt AC 722 ms 175468 KiB
test_0040.txt AC 721 ms 176804 KiB
test_0041.txt AC 722 ms 175232 KiB
test_0042.txt AC 718 ms 175140 KiB
test_0043.txt AC 722 ms 175780 KiB
test_0044.txt AC 721 ms 170916 KiB
test_0045.txt AC 720 ms 175004 KiB
test_0046.txt AC 713 ms 167896 KiB
test_0047.txt AC 724 ms 176284 KiB
test_0048.txt AC 719 ms 176552 KiB
test_0049.txt AC 711 ms 168032 KiB
test_0050.txt AC 718 ms 173496 KiB
test_0051.txt AC 718 ms 176812 KiB
test_0052.txt AC 716 ms 173228 KiB
test_0053.txt AC 717 ms 172876 KiB
test_0054.txt AC 714 ms 171520 KiB
test_0055.txt AC 722 ms 174868 KiB
test_0056.txt AC 712 ms 168180 KiB
test_0057.txt AC 719 ms 174868 KiB
test_0058.txt AC 714 ms 171656 KiB
test_0059.txt AC 724 ms 175532 KiB
test_0060.txt AC 718 ms 174916 KiB
test_0061.txt AC 717 ms 171176 KiB
test_0062.txt AC 719 ms 171304 KiB
test_0063.txt AC 724 ms 176280 KiB
test_0064.txt AC 718 ms 173232 KiB
test_0065.txt AC 713 ms 168068 KiB
test_0066.txt AC 719 ms 172908 KiB
test_0067.txt AC 720 ms 171964 KiB
test_0068.txt AC 712 ms 167980 KiB
test_0069.txt AC 723 ms 176400 KiB
test_0070.txt AC 716 ms 172992 KiB
test_0071.txt AC 713 ms 168044 KiB
test_0072.txt AC 721 ms 175040 KiB
test_0073.txt AC 718 ms 174864 KiB
test_0074.txt AC 721 ms 175120 KiB
test_0075.txt AC 719 ms 174796 KiB
test_0076.txt AC 718 ms 171040 KiB
test_0077.txt AC 720 ms 171432 KiB
test_0078.txt AC 721 ms 175380 KiB
test_0079.txt AC 720 ms 176668 KiB
test_0080.txt AC 723 ms 171400 KiB
test_0081.txt AC 713 ms 167536 KiB
test_0082.txt AC 724 ms 174844 KiB
test_0083.txt AC 718 ms 171164 KiB
test_0084.txt AC 726 ms 172856 KiB
test_0085.txt AC 719 ms 168076 KiB
test_0086.txt AC 723 ms 168104 KiB
test_0087.txt AC 709 ms 167852 KiB
test_0088.txt AC 717 ms 173076 KiB
test_0089.txt AC 721 ms 174744 KiB
test_0090.txt AC 720 ms 171304 KiB
test_0091.txt AC 718 ms 171796 KiB
test_0092.txt AC 721 ms 176792 KiB
test_0093.txt AC 721 ms 176200 KiB
test_0094.txt AC 714 ms 171548 KiB
test_0095.txt AC 717 ms 171420 KiB
test_0096.txt AC 715 ms 171784 KiB
test_0097.txt AC 722 ms 174760 KiB
test_0098.txt AC 711 ms 168032 KiB
test_0099.txt AC 715 ms 171456 KiB