알고리즘 스터디
[백준] 17779 게리맨더링 2 (C++)
coding_
2021. 10. 15. 17:45
728x90
반응형
백준 17779 게리맨더링 2
1. 문제
2. 접근법
[ 문제 접근 ]
지문에서 제시된 수식 조건만 잘 사용하여 1번 ~ 5번 선거구까지 정확하게 나누면 풀리는 문제였다.
선거구를 나누는 방법은 다음과 같다.
- 기준점 (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
위 조건을 사용하여 선거구를 나누고 각 선거구의 max, min값을 구해 차이의 가장 작은 값을 리턴하면 된다.
3. 코드
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n, sum;
int map[101][101];
int solve(int x, int y, int d1, int d2)
{
//경계선과 경계선안의 영역은 5번 선거구이므로
//5번 선거구를 담을 임시 배열 선언
int tmp[21][21] = { 0, };
tmp[x][y] = 5;
//경계선에 해당하는 영역에 5번 선거구 표시
/* (x+d1, y-d1), (x+d2+d1, y+d2-d1) */
for (int i = 1; i <= d1; ++i)
{
tmp[x + i][y - i] = 5;
tmp[x + d2 + i][y + d2 - i] = 5;
}
/* (x+d2, y+d2), (x+d1+d2, y-d1+d2) */
for (int i = 1; i <= d2; ++i)
{
tmp[x + i][y + i] = 5;
tmp[x + d1 + i][y - d1 + i] = 5;
}
//1번 선거구: 1 ≤ r < x+d1, 1 ≤ c ≤ y
int one = 0;
for (int r = 1; r < x + d1; ++r)
{
for (int c = 1; c <= y; ++c)
{
if (tmp[r][c] == 5)
break;
one += map[r][c];
}
}
//2번 선거구: 1 ≤ r ≤ x+d2, y < c ≤ N
int two = 0;
for (int r = 1; r <= x + d2; ++r)
{
for (int c = n; c > y; --c)
{
if (tmp[r][c] == 5)
break;
two += map[r][c];
}
}
//3번 선거구: x+d1 ≤ r ≤ N, 1 ≤ c < y-d1+d2
int three = 0;
for (int r = x + d1; r <= n; ++r)
{
for (int c = 1; c < y - d1 + d2; ++c)
{
if (tmp[r][c] == 5)
break;
three += map[r][c];
}
}
//4번 선거구: x+d2 < r ≤ N, y-d1+d2 ≤ c ≤ N
int four = 0;
for (int r = x + d2 + 1; r <= n; ++r)
{
for (int c = n; c >= y - d1 + d2; --c)
{
if (tmp[r][c] == 5)
break;
four += map[r][c];
}
}
//5번 선거구: 전체에서 나머지 인구를 빼면 됨
int five = sum - (one + two + three + four);
//인구가 가장 많은 선거구와 적은 선거구의 인구수를 구함
int maxi = max(one, max(two, max(three, max(four, five))));
int mini = min(one, min(two, min(three, min(four, five))));
//인구 차이 리턴
return (maxi - mini);
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
//최소값을 구하기 위한 변수
int ans = 987654321;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
//map을 입력받으면서 전체 인구수를 구함
cin >> map[i][j];
sum += map[i][j];
}
}
/* 지문에서 주어진 d1, d2의 조건에 따라 경계선을 구함
(d1, d2 ≥ 1, 1 ≤ x < x+d1+d2 ≤ N,
1 ≤ y-d1 < y < y+d2 ≤ N) */
for (int x = 1; x <= n; ++x)
{
for (int y = 1; y <= n; ++y)
{
for (int d1 = 1; d1 <= n; ++d1)
{
for (int d2 = 1; d2 <= n; ++d2)
{
if (x + d1 + d2 > n)
continue;
if (y - d1 < 1)
continue;
if (y + d2 > n)
continue;
//조건에 만족하는 경우 solve함수로 넘겨주고
//인구 차이의 최소값을 ans에 업데이트 시킴
ans = min(ans, solve(x, y, d1, d2));
}
}
}
}
cout << ans << "\n";
return 0;
}
4. 시간 복잡도
시뮬레이션 문제이므로 별도의 알고리즘을 사용하지 않고 풀었다.
4중 for문을 돌리면서 예외처리를 하여 조건에 만족하는 경우만 solve함수를 탄다. 또 n의 최댓값이 21이므로 1초 내에 구현 가능하다.
5. 결과
728x90
반응형