-
1. 문제
https://www.acmicpc.net/problem/15683
15683번: 감시
스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다. 1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할
www.acmicpc.net
2. 코드
#include "pch.h" #include <iostream> #include <queue> using namespace std; int n, m; int map[8][8]; vector<pair<int, int>> v; int head[5] = { 0,4,2,4,4 }; int vsize = 0; int mini = 987654321; void find(int cctv, int h, int x, int y); void dfs(int depth); void fourDir(int d, int x, int y); int main() { cin >> n >> m; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> map[i][j]; if (map[i][j] >= 1 && map[i][j] <= 4) v.push_back(make_pair(i, j)); } } vsize = v.size(); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (map[i][j] == 5) { fourDir(0, i, j); fourDir(1, i, j); fourDir(2, i, j); fourDir(3, i, j); } } } dfs(0); cout << mini; } void dfs(int depth) { if (depth == vsize) { int cnt = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (map[i][j] == 0) cnt++; } } mini = min(mini, cnt); return; } int x = v[depth].first; int y = v[depth].second; int cctv = map[x][y]; //map을 amap으로 복사 int amap[8][8]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { amap[i][j] = map[i][j]; } } for (int i = 0; i < head[cctv]; i++) { find(cctv, i, x, y); dfs(depth + 1); //cmap 초기화 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { map[i][j] = amap[i][j]; } } } } void find(int cctv, int h, int x, int y) { if (h == 0) { fourDir(0, x, y); if (cctv == 3 || cctv == 4) fourDir(1, x, y); if (cctv == 2 || cctv == 4) fourDir(2, x, y); } else if (h == 1) { fourDir(1, x, y); if (cctv == 3 || cctv == 4) fourDir(2, x, y); if (cctv == 2 || cctv == 4) fourDir(3, x, y); } else if (h == 2) { fourDir(2, x, y); if (cctv == 3 || cctv == 4) fourDir(3, x, y); if (cctv == 4) fourDir(0, x, y); } else if (h == 3) { fourDir(3, x, y); if (cctv == 3 || cctv == 4) fourDir(0, x, y); if (cctv == 4) fourDir(1, x, y); } } void fourDir(int d, int x, int y) { //우 if (d == 0) { for (int j = y + 1; j < m; j++) { if (map[x][j] == 6) break; if (map[x][j] == 0) map[x][j] = -1; } } //상 else if (d == 1) { for (int i = x - 1; i >= 0; i--) { if (map[i][y] == 6) break; if (map[i][y] == 0) map[i][y] = -1; } } //좌 else if (d == 2) { for (int j = y - 1; j >= 0; j--) { if (map[x][j] == 6) break; if (map[x][j] == 0) map[x][j] = -1; } } //하 else if (d == 3) { for (int i = x + 1; i < n; i++) { if (map[i][y] == 6) break; if (map[i][y] == 0) map[i][y] = -1; } } }
3. 후기
이 문제는 우선 경우의 수가 총 몇번이 나오는지 계산해야했다. 그래서 head라는 배열에 각 cctv마다 몇 번 회전해봐야 하는지 기록해 두었다. 5번 cctv는 회전해도 같으므로 미리 배열을 -1로 채워주고 1~4번 cctv만 dfs라는 함수에 넣어 재귀 형식으로 모든 경우의 수만큼 회전하도록 하였다.
fourDir는 단순히 상,하,좌,우 원하는 방향으로 벽을 만나기 전까지 -1로 채워주는 함수이고, find에서 cctv의 번호와 몇번째 회전인지를 따져서 알맞은 방향으로 -1를 채워 넣어준다.
'알고리즘 > 백준' 카테고리의 다른 글
3878 점분리 (라이브러리 사용 x) (0) 2019.09.01 2094 강수량 (라이브러리 사용 x) (0) 2019.09.01 16197 두 동전 (0) 2019.05.10 14502 연구소 (0) 2019.05.10 15685 드래곤커브 (0) 2019.05.08