https://www.acmicpc.net/problem/14502
시간 제한: 2초
메모리 제한 : 512MB
연구소의 크기는 NXM인 직사각형이며, 직사각형은 1x1 크기의 정사각형으로 이루어져있다. 각 정사각형은 빈칸이거나 벽이다. 일부 빈칸에는 바이러스가 존재하며 상하좌우로 인접한 빈칸으로 확산한다. 새로 세울 수 있는 벽은 3개이며, 꼭 3개를 세워야한다.
2 0 0 0 1 1 0
0 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
0은 빈칸, 1은 벽, 2는 바이러스를 의미한다. 벽을 세워 안전 영역의 크기의 최대값을 구해라.
입력
첫째 줄에는 지도의 세로크기 n과 가로 크기 m이 주어진다 (3 <= n,m <=8)
둘째 줄부터 N개의 줄에 지도 모양이 입력된다. (2 <= 바이러스의 개수 <=10)
빈칸의 개수는 3개 이상이다.
7 7
2 0 0 0 1 1 0
0 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
출력
얻을 수 있는 안전 영역의 최대 크기를 출력
27
import sys
input=sys.stdin.readline #데이터 입력의 빠른 처리를 위해 사용
from collections import deque #BFS를 사용하기 위해 큐를 사용하는데 deque를 통해 시간을 단축시킬 수 있다.
import copy
n,m=map(int,input().split())
lab=[] #연구소
wallp=[] #빈칸의 좌표를 저장하는 리스트
virus=[] # 바이러스의 좌표를 저장하는 리스트
dx=[-1,1,0,0]
dy=[0,0,-1,1]
for i in range(n):
lab.append(list(map(int,input().split())))
for j in range(m):
if lab[i][j] ==0:
wallp.append((i,j))
elif lab[i][j] ==2:
virus.append((i,j))
def bfs(lab):
q=deque(virus)
while q:
x,y=q.popleft()
for i in range(4):
nx = x +dx[i]
ny = y +dy[i]
if nx <0 or nx>=n or ny<0 or ny>=m or lab[nx][ny] !=0:
continue
lab[nx][ny]=2
q.append((nx,ny))
val=0
for i in range(n): #빈카의 개수 카운트
for j in range(m):
if lab[i][j]== 0:
val+=1
return val
answer=0
for i in range(len(wallp)-2):
for j in range(i+1,len(wallp)-1):
for w in range(j+1,len(wallp)): #연구소의 빈칸에 벽을 세워보는 모든 경우의 수를 고려
x1,y1=wallp[i]; x2,y2=wallp[j]; x3,y3=wallp[w]
if lab[x1][y1]!=0 or lab[x2][y2]!=0 or lab[x3][y3]!=0: #만약 벽을 세우려는 장소에 바이러스나 벽이 있다면 건너뛴다.
continue
tmplab=copy.deepcopy(lab)# 바이러스 확산이 원래의 연구소에 영향을 미치면 안되므로 임시 연구소를 생성
tmplab[x1][y1]=1; tmplab[x2][y2]=1; tmplab[x3][y3]=1 #임시 연수소에 벽을 세운다.
tmp=bfs(tmplab)
if answer<tmp: #빈칸의 개수가 지금까지의 최대값 보다 크다면 정답 값 갱신
answer=tmp
print(answer)
import sys
from collections import deque
from itertools import combinations
input=sys.stdin.readline
n,m=map(int,input().split())
lab=[]
wallp=[]
virus=[]
dx=[-1,1,0,0]
dy=[0,0,-1,1]
for i in range(n):
lab.append(list(map(int,input().split())))
for j in range(m):
if lab[i][j] ==0:
wallp.append((i,j))
elif lab[i][j] ==2:
virus.append((i,j))
answer=0
leng=len(wallp)
for combi in combinations(wallp,3):
tmplab=[arr[:] for arr in lab]
for x1,y1 in combi:
tmplab[x1][y1]=1
q=deque(virus)
tmp_leng=leng-3
while q:
x,y=q.popleft()
if answer > tmp_leng:
break
for i in range(4):
nx = x +dx[i]
ny = y +dy[i]
if 0<= nx < n and 0<= ny < m and tmplab[nx][ny] ==0:
tmplab[nx][ny]=2
q.append((nx,ny))
tmp_leng-=1
answer = max(answer,tmp_leng)
print(answer)
#기존의 코드
tmplab=copy.deepcopy(lab)
#바뀐 코드
tmplab=[arr[:] for arr in lab]
b=[1,2,[3,4,5]]
a=b[:]
a[0]=9
#결과값
a=[9,2,[3,4,5]], b=[1,2,[3,4,5]]
예를 들어 b=[1,2,[3,4,5]]이라는 리스트를 a=b[:]의 형태로 슬라이싱 할 경우, a와 b는 다른 리스트로 a[0]=9로 바꾼어도 b는 영향을 받지 않는다. 즉, a=[9,2,[3,4,5]] , b=[1,2,[3,4,5]]의 결과를 가진다.
a[2].append(1)
#결과값
a=[1,2,[3,4,5,1]], b=[1,2,[3,4,5,1]]
하지만 a[2].append(1)을 했을 경우에는 a와 b 모두 [1,2,[3,4,5,1]]로 값이 바뀌게 된다. 그 이유는 a의 원소 [3,4,5]와 b의 원소 [3,4,5]가 같은 리스트를 가리키기 때문이다.
tmplab=[arr[:] for arr in lab]은 리스트 컴프리헨션을 통해 그 안의 리스트를 슬라이싱해서 리스트안의 리스트까지 서로 다른 리스트를 만드는 방법이다.
#기존의 코드
x1,y1=wallp[i]; x2,y2=wallp[j]; x3,y3=wallp[w]
(...)
tmplab[x1][y1]=1; tmplab[x2][y2]=1; tmplab[x3][y3]=1
#바뀐 코드
for x1,y1 in combi:
tmplab[x1][y1]=1