백준 15683 - 감시
Updated:
C++
15683 번 - 감시
문제
사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오. 문제 출처
접근 방법
- 먼저 모든 cctv의 정보(위치, 타입)을 저장한다.
- DFS를 이용하여 cctv가 바라보는 방향을 모든 경우로 설정해준다. - 이의 경우 cctv의 방향과 상관없이 시계방향으로 한번씩 돌려준다고 생각하면 된다.
- 이제 cctv의 정보를 통하여 하나씩 감시방향을 설정해 준다.
- 각 cctv들이 감시하였다고 표시한 지도를 통하여 사각지대의 수를 찾는다.
- 다시 초기 지도의 상태로 돌아가 다음 경우의 수로 사각지대의 수를 찾는다.
구현
Main()
지도를 하나씩 graph에 넣으면서, 만약 cctv가 인식이 되면 cctv
에 좌표와 그 cctv의 타입을 저장한다.
또한 direct
에 방향을 설정하는데 초기는 오른쪽을 나타내는 0을 저장한다.
direct
는 0, 1, 2, 3까지 저장되며, 차례대로 오른쪽에서 부터 시계방향으로 돈다고 생각한다.
DFS()
DFS의 조건으로 cctv의 개수 만큼 설정하였을 때, Cal()
함수를 호출하게 하였다. 모든 cctv를 다 사용하며, 각 cctv의 할당한 순서는 같으므로, 변수 cctv
와 direct
의 인덱스가 같다고 생각하면 된다.
Cal()
cctv들의 좌표와 타입, 그리고 방향을 하나씩 받아 어느 위치에 감시할 것인지 설정하는 함수이다.
각 타입에 따라 switch - case를 사용하여 구분한다.
각 타입은 현 위치에서 감시하는 방향을 (drt
) 돌리면서 구현한다.
예를 들어, type 2인 경우 현재 방향에서 한번, 반대 편으로 한번 쭉 일자로 감시를 하며, type 4인 경우 시게 방향으로 3번 cctv 화면을 돌려서 감시를 한다.
drt
는 0, 1, 2, 3 중에 하나이며, 각 타입에 따라 drt를 변경해준다.
또한 4를 넘지 않게 해준다.
watch()
cctv 위치에서 drt 방향으로 벽을 만날 때 까지 일자로 7
로 만들어 주며 감시를 구현한다.
getResult()
사각지대를 찾으며, 가장 적은 사각 지대 일 때 result
를 갱신한다.
코드
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define MAX 1e9
int n, m, result = MAX;
int graph[8][8]; //지도
int saved[8][8]; //백업 지도
vector<pair<pair<int, int>, int>> cctv; //cctv의 위치와 타입을 저장 하는 객체
vector<int> direct; //cctv가 바라보는 방향
int dy[4] = { 0, 1, 0, -1 }; //우, 하, 좌, 상
int dx[4] = { 1, 0, -1, 0 };
void DFS(int lv); //각 cctv들의 방향을 설정하는 DFS
void Cal(); //cctv의 정보와 방향을 통해 감시 지역을 설정하는 함수
void watch(int y, int x, int drt); //받은 정보를 통해 감시지역을 계산하는 함수
void copyGraph(); //지도 초기화
void getResult(); //0의 수를 세어, 사각지대의 수를 계산
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
cin >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> graph[i][j];
saved[i][j] = graph[i][j];
if (graph[i][j] > 0 && graph[i][j] != 6) {
cctv.push_back(make_pair(make_pair(i, j), graph[i][j]));
direct.push_back(0);
}
}
}
DFS(0);
cout << result;
return 0;
}
void DFS(int lv) {
if (lv == cctv.size()) {
Cal();
getResult();
copyGraph();
return;
}
for (int j = 0; j < 4; j++) {
direct.at(lv) = j;
DFS(lv + 1);
}
}
void Cal() {
for (int i = 0; i < cctv.size(); i++) {
int y = cctv.at(i).first.first;
int x = cctv.at(i).first.second;
int type = cctv.at(i).second;
int drt = direct.at(i);
switch (type) {
case 1:
watch(y, x, drt);
break;
case 2:
for (int i = 0; i < 2; i++) {
watch(y, x, drt);
drt += 2;
if (drt >= 4) {
drt -= 4;
}
}
break;
case 3:
for (int i = 0; i < 2; i++) {
watch(y, x, drt);
drt += 1;
if (drt >= 4) {
drt -= 4;
}
}
break;
case 4:
for (int i = 0; i < 3; i++) {
watch(y, x, drt);
drt += 1;
if (drt >= 4) {
drt -= 4;
}
}
break;
case 5:
for (int i = 0; i < 4; i++) {
watch(y, x, drt);
drt += 1;
if (drt >= 4) {
drt -= 4;
}
}
break;
}
}
}
void watch(int y, int x, int drt) {
int curY = y;
int curX = x;
while (1) {
curY += dy[drt];
curX += dx[drt];
if (curY == -1 || curY == n || curX == -1 || curX == m || graph[curY][curX] == 6) {
break;
}
else {
graph[curY][curX] = 7;
}
}
}
void copyGraph() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
graph[i][j] = saved[i][j];
}
}
}
void getResult() {
int temp = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (graph[i][j] == 0)
temp++;
}
}
result = min(result, temp);
}
후기 및 개선할 점
며칠을 걸려 풀었으며, 나만의 방식으로 풀었다는 것에 의의를 둔다.