일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- SQL
- 개발남노씨
- 트랜잭션
- 데이터베이스
- 쉬운 코드
- concurrency control
- 네트워크
- recoverability
- 반효경
- 백엔드
- 온디바이스AI
- Extendable hashing
- 시스템프로그래밍
- 프로세스 주소 공간
- SDK
- 커널 동기화
- 인터럽트
- B tree 데이터삽입
- 쉬운코드
- 코딩테스트 [ ALL IN ONE ]
- 김영한
- 갤럭시 S24
- vite
- 코딩애플
- BreadcrumbsComputer-Networking_A-Top-Down-Approach
- CPU 스케줄링
- 운영체제
- Git
- 시그널 핸들러
- 운영체제와 정보기술의 원리
- Today
- Total
티끌모아 태산
17779: 게리맨더링 2 본문
https://www.acmicpc.net/problem/17779
17779번: 게리맨더링 2
재현시의 시장 구재현은 지난 몇 년간 게리맨더링을 통해서 자신의 당에게 유리하게 선거구를 획정했다. 견제할 권력이 없어진 구재현은 권력을 매우 부당하게 행사했고, 심지어는 시의 이름도
www.acmicpc.net
설명
재현시는 크기가 N×N인 격자로 나타낼 수 있다. 격자의 각 칸은 구역을 의미하고, r행 c열에 있는 구역은 (r, c)로 나타낼 수 있다. 구역을 다섯 개의 선거구로 나눠야 하고, 각 구역은 다섯 선거구 중 하나에 포함되어야 한다. 선거구는 구역을 적어도 하나 포함해야 하고, 한 선거구에 포함되어 있는 구역은 모두 연결되어 있어야 한다. 구역 A에서 인접한 구역을 통해서 구역 B로 갈 수 있을 때, 두 구역은 연결되어 있다고 한다. 중간에 통하는 인접한 구역은 0개 이상이어야 하고, 모두 같은 선거구에 포함된 구역이어야 한다.
선거구를 나누는 방법은 다음과 같다.
- 기준점 (x, y)와 경계의 길이 d1, d2를 정한다. (d1, d2 ≥ 1, 1 ≤ x < x+d1+d2 ≤ N, 1 ≤ y-d1 < y < y+d2 ≤ N)
- 다음 칸은 경계선이다.
- (x, y), (x+1, y-1), ..., (x+d1, y-d1)
- (x, y), (x+1, y+1), ..., (x+d2, y+d2)
- (x+d1, y-d1), (x+d1+1, y-d1+1), ... (x+d1+d2, y-d1+d2)
- (x+d2, y+d2), (x+d2+1, y+d2-1), ..., (x+d2+d1, y+d2-d1)
- 경계선과 경계선의 안에 포함되어있는 곳은 5번 선거구이다.
- 5번 선거구에 포함되지 않은 구역 (r, c)의 선거구 번호는 다음 기준을 따른다.
- 1번 선거구: 1 ≤ r < x+d1, 1 ≤ c ≤ y
- 2번 선거구: 1 ≤ r ≤ x+d2, y < c ≤ N
- 3번 선거구: x+d1 ≤ r ≤ N, 1 ≤ c < y-d1+d2
- 4번 선거구: x+d2 < r ≤ N, y-d1+d2 ≤ c ≤ N
구역 (r, c)의 인구는 A[r][c]이고, 선거구의 인구는 선거구에 포함된 구역의 인구를 모두 합한 값이다. 선거구를 나누는 방법 중에서, 인구가 가장 많은 선거구와 가장 적은 선거구의 인구 차이의 최솟값을 구해보자.
핵심 아이디어
이 문제는 완전탐색, 구현 문제이다. 기준점 x,y와 경계의 길이 d1,d2가 가질수 있는 모든 조합을 다 탐색해서 선거구끼리 인구수 차이의 최솟값을 구해주면 된다. 각 변수들이 가질 수 있는 범위는 1 ~ n 까지이고, 문제에서 제공한 변수의 조건만 만족하면 모두 후보가 될 수 있다. 모든 조합을 탐색하면서 함수를 실행시켜 최솟값을 업데이트해주면 된다.
함수: 선거구당 인구수를 저장하는 배열과 각 좌표가 어떤 선거구인지를 알려주는 배열을 선언한다. 입력으로 들어온 x,y,d1,d2에 대해서 경계선에 해당하는 부분을 5번 선거구로 지정해준다. 그 다음 경계선 내부에 대해서는 행을 탐색하면서 경계선을 만나면 그 다음 경계선을 만날때까지 5번 선거구로 지정해주면되는데, 이는 bool값을 이용하면 된다. 그리고 5번 선거구를 구했으면, 5번 선거구에 포함되지 않은 영역중 각 선거구의 범위에 해당하는 부분을 지정해 주면 된다.
- 선거구당 인구수, 각 좌표가 어떤 선거구인지 알려주는 배열 선언
- 5번 선거구를 먼저 지정해 준다.
- 그 후 나머지 선거구를 지정해 주면 된다.
코드 구현
1. 초기 맵 선언하고 입력받기
처음에 맵을 설정하는 과정에서 1번 index부터 시작하기 위해 조정을 고려하여 맵을 설정했는데, index 범위 초과 결과가 나서 잠깐 헷갈렸었다.
n = int(input())
graph = [[]]
for _ in range(n):
graph.append([0] + list(map(int, input().split())))
'''
[]
[0, 1, 2, 3, 4, 1, 6]
[0, 7, 8, 9, 1, 4, 2]
[0, 2, 3, 4, 1, 1, 3]
[0, 6, 6, 6, 6, 9, 4]
[0, 9, 1, 9, 1, 9, 5]
[0, 1, 1, 1, 1, 9, 9]
'''
n = int(input())
graph = [[0] + list(map(int, input().split())) for _ in range(n)]
'''
[0, 1, 2, 3, 4, 1, 6]
[0, 7, 8, 9, 1, 4, 2]
[0, 2, 3, 4, 1, 1, 3]
[0, 6, 6, 6, 6, 9, 4]
[0, 9, 1, 9, 1, 9, 5]
[0, 1, 1, 1, 1, 9, 9]
'''
2. 완전 탐색
ans = int(1e9)
# 완전 탐색: 기준점, 경계 조합을 모두 탐색해서 각 조합마다 최소시간을 비교해서 업데이트
for x in range(1, n+1):
for y in range(1, n+1):
# d1,d2 >= 1
for d1 in range(1, n+1):
for d2 in range(1, n+1):
# 주어진 조건을 만족한다면
if (1 <= x < x + d1 + d2 <= n) and (1 <= y-d1<y<y+d2<=n):
ans = min(ans, cal(x,y,d1,d2))
print(ans)
주어진 조건 1을 잘 파악해서 작성하면 된다.
3. 주거진 조건에 따라 선거구를 나누고 최대인원 최소인원의 차를 구하느 함수
def cal(x,y,d1,d2):
# 각 선거구 마다 총 인원을 저장하는 배열
arr = [[0] for _ in range(5)] # 선거구는 1 ~ 5로 총 5개
# 선거구
temp = [[0] * (n+1) for _ in range(n+1)]
# 먼저 5번 선거구를 지정한다. 경계 구하기
for i in range(d1+1):
temp[x+i][y+i] = 5 # 1번 조건
temp[x+d2+i][y+d2-i] = 5 # 3번 조건
#
for i in range(d2+1): # 기준점 계산을 위해 0부터 시작
temp[x+i][y+i] = 5 # 2번 조건
temp[x+d1+i][y+i-d1] =5 # 4번 조건
# 5번 경계선 내부에 5번 선거구 할당
for i in range(x + 1, x + d1 + d2): # 예시 1번 기준 행 3,4,5
flag = False
# 행을 기준으로 한번 경계 구역을 만나면
for j in range(1, n + 1):
if temp[i][j] == 5: # 경계
flag = not flag # 다시 경계구역을 만날 때 까지
if flag:
temp[i][j] = 5 # 5번 구역
# 이제 선거구 지정하기
for r in range(1, n+1):
for c in range(1, n+1):
if r < x + d1 and c <= y and temp[r][c] == 0: # 5번 선거구가 아니라는 뜻
arr[0] += graph[r][c] # 1번 선거구
elif r <= x + d2 and y < c and temp[r][c] == 0:
arr[1] += graph[r][c] # 2번 선거구
elif x + d1 <= r and c < y - d1 + d2 and temp[r][c] == 0:
arr[2] += graph[r][c] # 3번 선거구
elif x + d2 < r and y - d1 + d2 <=c and temp[r][c] == 0:
arr[3] += graph[r][c]
elif temp[r][c] == 5: # 5번 선거구라면
arr[4] += graph[r][c]
return max(arr) - min(arr)
여기서 주의할 점은 flag = True로 바꾸면 안된다. not flag라 해야지 처음 이후의 5번 경계를 다시 만났을 때 False로 바꾸어 5를 영역안에 넣는 반복과정을 멈추게 된다.
'백준 문제 > 삼성 기출' 카테고리의 다른 글
17141: 연구소 2 (0) | 2024.03.21 |
---|---|
17142: 연구소 3 (0) | 2024.03.19 |
21609: 상어 중학교 (0) | 2024.03.18 |