너와!나의!알고!리즘!/백준

[백준 #14500,Python] 테트로미노

moongchi98 2021. 5. 13. 23:59

[문제]

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다.

  • 정사각형은 서로 겹치면 안 된다.
  • 도형은 모두 연결되어 있어야 한다.
  • 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다.

정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다.

아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누어져 있으며, 각각의 칸에는 정수가 하나 쓰여 있다.

테트로미노 하나를 적절히 놓아서 테트로미노가 놓인 칸에 쓰여 있는 수들의 합을 최대로 하는 프로그램을 작성하시오.

테트로미노는 반드시 한 정사각형이 정확히 하나의 칸을 포함하도록 놓아야 하며, 회전이나 대칭을 시켜도 된다.

[풀이]

처음에는 저 모든 테트로미노를 여기에 채워넣어야 하는 문제인줄 알고,,문제를 골라주신 동건이형이 나를 과대평가 한거 아닐까,,? 라고 생각했다 ^^,, 근데 그냥 간단하게 저 모양으로 가능한 모든 숫자 4개의 합을 결정하면 된당.

처음에는 어제 푼 소문난 칠공주처럼 하면 딱이다! 하고 만들었다. (4가지 조합 다 만들고, 이웃 점검) 그런데 답은 맞게 나오는 거 같은데 시간초과가 난다^^,,그것두 1%도 올라가지 않음 참눼^^,,,, 그래서 아,.,,어쩌지 하다가 다른 분들의 풀이를 참고해서 모든 경우의 수를 만들면 된다는 것을 알았다.. 유레카!

 

🐰 모든 조합의 수 만들어서 한 풀이

from sys import stdin
N,M = map(int,stdin.readline().split())

arr = [list(map(int,stdin.readline().split())) for _ in range(N)]

all_kind= [
    [(0, 0), (0, 1), (1, 0), (1, 1)],  # ㅁ
    [(0, 0), (0, 1), (0, 2), (0, 3)],  # ㅡ
    [(0, 0), (1, 0), (2, 0), (3, 0)],  # ㅣ
    [(0, 0), (0, 1), (0, 2), (1, 0)],
    [(1, 0), (1, 1), (1, 2), (0, 2)],
    [(0, 0), (1, 0), (1, 1), (1, 2)],  # ㄴ
    [(0, 0), (0, 1), (0, 2), (1, 2)],  # ㄱ
    [(0, 0), (1, 0), (2, 0), (2, 1)],
    [(2, 0), (2, 1), (1, 1), (0, 1)],
    [(0, 0), (0, 1), (1, 0), (2, 0)],
    [(0, 0), (0, 1), (1, 1), (2, 1)],
    [(0, 0), (0, 1), (0, 2), (1, 1)],  # ㅜ
    [(1, 0), (1, 1), (1, 2), (0, 1)],  # ㅗ
    [(0, 0), (1, 0), (2, 0), (1, 1)],  # ㅏ
    [(1, 0), (0, 1), (1, 1), (2, 1)],  # ㅓ
    [(1, 0), (2, 0), (0, 1), (1, 1)],
    [(0, 0), (1, 0), (1, 1), (2, 1)],
    [(1, 0), (0, 1), (1, 1), (0, 2)],
    [(0, 0), (0, 1), (1, 1), (1, 2)]]
max_total = 0
for i in range(N):
    for j in range(M):
        for s in all_kind:
            total = 0
            for x in range(4):
                nr = i + s[x][0]
                nc = j + s[x][1]
                if 0<=nr<N and 0<=nc<M:
                    total += arr[nr][nc]
            if total > max_total:
                max_total = total
print(max_total)

 

🐤 소문난 칠공주 처럼 모든 조합 만들고, 이웃 찾기 => 시간 초과 코드

#시간초과
from sys import stdin
def combi(idx,total,q,i):
    global max_total,visit_check
    if i>=N*M or N*M-i<4-idx:
        return
    if idx == 4:
        if total > max_total:
            check(q[0],q)
            if sum(sum(visit_check,[])) == 4:
                max_total = total
            visit_check =[[0]*M for _ in range(N)]
        return
    tmp.append(i)
    combi(idx+1,total+arr[i],q+[i],i+1)
    tmp.pop()
    combi(idx,total,q,i+1)

def check(s,q):
    q = set(q)
    r = s // M
    c = s % M
    visit_check[r][c] = 1
    for i in range(4):
        nr = r + dr[i]
        nc = c + dc[i]
        if 0<=nr<N and 0<=nc<M and visit_check[nr][nc] == 0:
            next = (nr*M+nc)
            if next in q:
                check(next,q)
N,M = map(int,stdin.readline().split())
arr =[]
for _ in range(N):
    arr += list(map(int,stdin.readline().split()))
visit = [0]*(N*M)
visit_check =[[0]*M for _ in range(N)]
dr = [-1,1,0,0]
dc = [0,0,-1,1]
tmp = []
max_total = 0
combi(0,0,[],0)
print(max_total)