[Samsung] 2022-2 오후 2번 산타의 선물공장 2
[Samsung] 2022-2 오후 2번 산타의 선물공장 2
Question
Language: Python
Difficulty: Platinum 5
해당 문제는 삼성 오전 2번와 동일한 문제로 doubly linked list을 직접적으로 구현해서 문제를 풀이해야 시간 복잡도 내 풀이가 가능하다. 각 노드에 대한 컨테이너 인덱스를 저장해서 특정 노드의 위치를 파악할 때 시간 효율성을 높이도록 한다.
이중 연결리스트 초기화
doubly linked list을 초기화 하는 부분으로, 노드를 생성하고 컨테이너에 노드들을 삽입한다.
def insert_into_container(heads,tails,nodes,container_counts,index,container):
node=Node(index)
#만약 컨테이너에 노드가 없는 경우
if container_counts[container]==0:
heads[container]=node
#그렇지 않은 경우, tail 뒤에 새로운 노드를 붙인다.
else:
tails[container].right=node
node.left=tails[container]
tails[container]=node
container_counts[container]+=1
nodes[index]=node
특정 컨테이너에 노드를 넣는 함수
출발지 컨테이너에서 노드를 빼내서 목적지 컨테이너에 노드를 추가하는 작업을 함수로 구현했다. 출발지 컨테이너가 비는 경우와 목적지가 빈 경우를 고려하여 상황에 맞게 처리한다. 노드 갯수에 상관없이 head, tail만 지정하면 head <-> tail 부분을 목적지 헤드로 이동시킨다.
#컨테이너에 노드 여러개를 삽입
def move_nodes_to_container(heads,tails,container_counts,src,dest,head,tail,moving_counts):
dest_head=heads[dest]
#목적지 컨테이너가 비어있는 경우
if dest_head==None:
tails[dest]=tail
#그렇지 않은 경우 head의 앞에 연결
else:
dest_head.left=tail
#이동 후 출발지 컨테이너에 남아있는 박스가 없는 경우
if tail.right == None:
tails[src]=None
#그렇지 않은경우 head <-> tail 부분에서 tail의 연결을 끝는다.
else:
tail.right.left=None
heads[src]=tail.right
tail.right=dest_head
heads[dest]=head
container_counts[dest]+=moving_counts
container_counts[src]-=moving_counts
헤드를 서로 교체하는 함수
두 개의 컨테이너에 대해 서로의 헤드를 교체하는 함수
def swith_heads(heads,tails,container_counts,src,dest):
source_head=heads[src]
dest_head=heads[dest]
#목적지 헤드 뒤에 박스가 없는 경우 tails 값을 바꾼다.
if dest_head.right==None:
tails[dest]=source_head
#그렇지 않은 경우, 목적지 헤드와 연결
else:
dest_head.right.left=source_head
#출발지 헤드 뒤에 박스가 없으면 tails 바꾸기
if source_head.right == None:
tails[src]=dest_head
#그렇지 않은 경우, 목적지 헤드와 연결
else:
source_head.right.left=dest_head
#서로의 위치 이동
dest_head.right,source_head.right=source_head.right,dest_head.right
heads[dest]=source_head
heads[src]=dest_head
위의 함수들을 활용하면 문제의 조건에 따른 시뮬레이션을 구현하는 것이 가능하다.
Solution
class Node:
def __init__(self,id):
self.id=id
self.left=None
self.right=None
def __str__(self):
return "[Node: %d]" % (self.id)
#초기, 컨테이너에 박스를 추가하기 위한 함수
def insert_into_container(heads,tails,nodes,container_counts,index,container):
node=Node(index)
#만약 컨테이너에 노드가 없는 경우
if container_counts[container]==0:
heads[container]=node
else:
tails[container].right=node
node.left=tails[container]
tails[container]=node
container_counts[container]+=1
nodes[index]=node
#컨테이너에 노드 삽입
def move_nodes_to_container(heads,tails,container_counts,src,dest,head,tail,moving_counts):
dest_head=heads[dest]
#목적지 컨테이너가 비어있는 경우
if dest_head==None:
tails[dest]=tail
#그렇지 않은 경우 head의 앞에 연결
else:
dest_head.left=tail
#이동 후 출발지 컨테이너에 남아있는 박스가 없는 경우
if tail.right == None:
tails[src]=None
#그렇지 않은경우 head <-> tail 부분에서 tail의 연결을 끝는다.
else:
tail.right.left=None
heads[src]=tail.right
tail.right=dest_head
heads[dest]=head
container_counts[dest]+=moving_counts
container_counts[src]-=moving_counts
#서로의 헤드를 바꾸는 함수
def swith_heads(heads,tails,container_counts,src,dest):
source_head=heads[src]
dest_head=heads[dest]
#목적지 헤드 뒤에 박스가 없는 경우 tails 값을 바꾼다.
if dest_head.right==None:
tails[dest]=source_head
#그렇지 않은 경우, 목적지 헤드와 연결
else:
dest_head.right.left=source_head
#출발지 헤드 뒤에 박스가 없으면 tails 바꾸기
if source_head.right == None:
tails[src]=dest_head
#그렇지 않은 경우, 목적지 헤드와 연결
else:
source_head.right.left=dest_head
#서로의 위치 이동
dest_head.right,source_head.right=source_head.right,dest_head.right
heads[dest]=source_head
heads[src]=dest_head
def solution():
n_containers,n_nodes=queries[0][1],queries[0][2]
init_nodes=queries[0][3:]
container_counts=[0]*n_containers
heads=[None] * n_containers
tails=[None] * n_containers
nodes=[None] * n_nodes
#벨트 초기화 작업 진행
for index in range(n_nodes):
container=init_nodes[index]-1
insert_into_container(heads,tails,nodes,container_counts,index,container)
for index in range(1,n):
command=queries[index][0]
#물건 옮기기
if command == 200:
src,dest=map(lambda x: x-1,queries[index][1:])
#출발지가 빈 경우에는 옮기지 않는다.
if heads[src] == None:
print(container_counts[dest])
continue
#출발지 헤드에 있는 모든 노드를 옮긴다.
move_nodes_to_container(heads,tails,container_counts,src,dest,heads[src],tails[src],container_counts[src])
print(container_counts[dest])
#앞 물건만 교체
if command == 300:
src,dest=map(lambda x: x-1,queries[index][1:])
#두 개의 컨테이너가 모두 빈 경우에는 이동하지 않는다.
if heads[src]==None and heads[dest]==None:
print(container_counts[dest])
continue
#출발지가 빈 경우
elif heads[src]==None:
move_nodes_to_container(heads,tails,container_counts,dest,src,heads[dest],heads[dest],1)
#목적지가 빈 경우
elif heads[dest]==None:
move_nodes_to_container(heads,tails,container_counts,src,dest,heads[src],heads[src],1)
#둘다 차있는경우 서로의 헤드를 변경한다.
else:
swith_heads(heads,tails,container_counts,src,dest)
print(container_counts[dest])
#물건 나누기
if command == 400:
src,dest=map(lambda x: x-1,queries[index][1:])
#만약 src container에 박스 갯수가 1개 이하인 경우 이동하지 않는다.
if container_counts[src] <=1:
print(container_counts[dest])
continue
moving_counts=container_counts[src]//2
head=heads[src]
tail=heads[src]
#n//2 위치를 파악하기 위해 tail 이동
for _ in range(moving_counts-1):
tail=tail.right
move_nodes_to_container(heads,tails,container_counts,src,dest,head,tail,moving_counts)
print(container_counts[dest])
#선물 정보 출력
if command == 500:
item_id=queries[index][1]-1
node=nodes[item_id]
a,b=-1,-1
a=node.left.id+1 if node.left != None else -1
b=node.right.id+1 if node.right !=None else -1
print(a+2*b)
#벨트 정보 출력
if command == 600:
container_id=queries[index][1]-1
c=container_counts[container_id]
a=heads[container_id].id+1 if c!=0 else -1
b=tails[container_id].id+1 if c!=0 else -1
print(a+2*b+3*c)
if __name__ == "__main__":
n=int(input())
queries=[list(map(int,input().split())) for _ in range(n)]
solution()
댓글남기기