[BOJ]200056-魔法使いサメと火球💥


サムスンはサメシリーズの第1発を出して、
質問リンク
20056-魔法使いサメと火球
問題の説明
ガイドサメはN*NサイズのメッシュでM個の火球を移動します.火球iは、初期位置(ri,ci)(r i,c i)(ri,ci)に質量mim imi、方向did idi、速度sis isiを入力とする.サメが移動命令を出したら
  • すべての火球がdod idiの方向にsis isi格子を移動する
    ->移動中に同じ部屋に複数の火の玉が存在する場合があります
  • 移動後、1つの部屋に2つ以上の火球があれば
    2.1統合
    2.2火の玉を4つに分ける
    -質量=合成火の玉質量の合計/5
    -速度=合成火炎球速度の合計/合成火炎球数
    -方向=すべての火の玉の方向が奇数または偶数の場合、0、2、4、6または1、3、5、7
    2.3質量が0の場合、火の玉は
  • に消える
    移動命令の順序が与えられた場合、k回命令後の残りの火球質量の総和は?
    問題を解く
    私の言うとおりにすればいい模擬問題ですが、デバッグに時間がかかりました^ㅜこのような問題はコードで設計を優先するより、正しい設計と解題習慣を身につけなければなりません.
  • ボード[i][j]:(i,j)位置にある火球情報を含むリスト
  • 入力の受信
    for i in range(M):
        r, c, m, s, d = map(int, input().split())
        board[r-1][c-1].append([m, s, d, -1])
    1≦ri,ci≦N,r−1,c−1の処理が必要であり,
    i次コマンドで火球を移動
    # 1. 모든 파이어볼에 대해서 방향 d로 s만큼 이동하기 
        for i in range(N):
            for j in range(N):
                for f in range(len(board[i][j])):
                    fireball = board[i][j].pop(0)
                    nx, ny = i, j
                    m, s, d, moves = fireball
                    if moves != move:
                        nx, ny = move_fireball(i, j, m, s, d)
                    board[nx][ny].append([m, s, d, move])
    move fireball関数を使用して、各火球を移動した結果を計算し、グリッド全体でこの情報を更新します.
    移動を実現する関数は次のとおりです.
    def move_fireball(x, y, m, s, d):
        # d방향으로 s만큼 이동시키기 (m, s, d)
        nx, ny = (x+dx[d]*s)%N, (y+dy[d]*s)%N
        return nx, ny
    グリッドの行と列は1からN番号、1行はN番号、1列はN番号に関連付けられます.
    従って、元座標+方向dにsを移動する値をNで割った残りの部分が座標となる.
    移動後に1つの格子に2つ以上の火球処理がある
    # 2. 이동 후 한칸에 2개이상 존재하는지
        for i in range(N):
            for j in range(N):
                if len(board[i][j]) > 1: 
                    length = len(board[i][j])
                    # 2개 이상이면
                    sumM, sumS, oddcount, evencount = 0, 0, 0, 0
                    for f in board[i][j]:
                        sumM += f[0]
                        sumS += f[1]
                        if f[2] % 2 == 0:
                            evencount += 1
                        else:
                            oddcount += 1
                    # 나눈 뒤 질량이 0보다 크면 4개로 나누기
                    if sumM // 5 != 0:
                        m, s = sumM//5, sumS//length
                        if oddcount == 0 or evencount == 0:
                            # 전부 홀수거나 짝수면
                            board[i][j] = [[m,s,0,move], [m,s,2,move], [m,s,4,move], [m,s,6,move]]
                        else:
                            board[i][j] = [[m,s,1,move], [m,s,3,move], [m,s,5,move], [m,s,7,move]]
                    # 아니면 전체 소멸
                    else:
                        board[i][j] = []
    すべての格子を回って、格子に火球が2つ以上ある場合は、指定された方法で処理します.oddcountとevencountを使用して、セル内のすべての火球の方向が穴/偶の部分であるかどうかを実現します.oddcountまたはevencountがそのセルの火球数に等しい場合は、条件を満たすことを示すので、方向を0、2、4、6、または1、3、5、7に追加します.
    完全なコード
    コード全体を以下に示します.
    import sys
    
    input = sys.stdin.readline
    
    N, M, K = map(int, input().split())
    board = [[[] for _ in range(N)] for _ in range(N)]
    dx = [-1, -1, 0, 1, 1, 1, 0, -1]
    dy = [0, 1, 1, 1, 0, -1, -1, -1]
    
    def move_fireball(x, y, m, s, d):
        # d방향으로 s만큼 이동시키기 (m, s, d)
        nx, ny = (x+dx[d]*s)%N, (y+dy[d]*s)%N
        return nx, ny
    
    for i in range(M):
        r, c, m, s, d = map(int, input().split())
        board[r-1][c-1].append([m, s, d, -1])
    
    for move in range(K):
        # 1. 모든 파이어볼에 대해서 방향 d로 s만큼 이동하기 
        for i in range(N):
            for j in range(N):
                for f in range(len(board[i][j])):
                    fireball = board[i][j].pop(0)
                    nx, ny = i, j
                    m, s, d, moves = fireball
                    if moves != move:
                        nx, ny = move_fireball(i, j, m, s, d)
                    board[nx][ny].append([m, s, d, move])
    
        # 2. 이동 후 한칸에 2개이상 존재하는지
        for i in range(N):
            for j in range(N):
                if len(board[i][j]) > 1: 
                    length = len(board[i][j])
                    # 2개 이상이면
                    sumM, sumS, oddcount, evencount = 0, 0, 0, 0
                    for f in board[i][j]:
                        sumM += f[0]
                        sumS += f[1]
                        if f[2] % 2 == 0:
                            evencount += 1
                        else:
                            oddcount += 1
                    # 나눈 뒤 질량이 0보다 크면 4개로 나누기
                    if sumM // 5 != 0:
                        m, s = sumM//5, sumS//length
                        if oddcount == 0 or evencount == 0:
                            # 전부 홀수거나 짝수면
                            board[i][j] = [[m,s,0,move], [m,s,2,move], [m,s,4,move], [m,s,6,move]]
                        else:
                            board[i][j] = [[m,s,1,move], [m,s,3,move], [m,s,5,move], [m,s,7,move]]
                    # 아니면 전체 소멸
                    else:
                        board[i][j] = []
    
    answer = 0
    for i in range(N):
        for j in range(N):
            for f in board[i][j]:
                answer += f[0]
    
    print(answer)
    プロセス長の実施問題は容易ではなく、