코딩공작소
[백준]감시 본문
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
처음 볼때는 아예 접근방법도 모르고 너무 복잡하다고 생각했었다..
근데 막상 좀 제대로 풀고나니까 1시간정도 걸렸었다.
가장 중요한 것은 카메라들의 방향에 대해서 완전탐색(순열)을 해주는 것이다.
각 카메라타입마다 약간의 다른방식이지만 재귀함수를 이용해 중복순열을 구현해주었다.
그리고 가장 핵심인 부분이 카메라로 감시를 하는 부분인데, 처음에는 각 카메라 마다 각 방향에 따라
구현을 해주어야 하나 너무 복잡해서 가만히 생각을 해보았다.
그냥 한 방향으로 쭉 감시하는 함수를 하나 만들어서 여러번 사용해주면 되겠다는 생각이 핵심이었던거 같다.
그리고 백업배열을 만드는건 이젠 익숙해 져서 어렵지 않았다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
/*
1.각각의 카메라 상태들에 대해서 완전탐색을 해야함. 카메라갯수^4 개가 있다.
2.백업 배열이 필요하다
3.5번째 카메라가 들어오면 바로 + 처리하고 신경안쓴다.
4.2번은 2방향 나머지는 4방향이다.
5.카메라가 최대한 많이봐야함. 사각지대가 최소여야함.
*/
struct Cam {
int r, c;
int type;
Cam() {};
Cam(int r, int c, int type) :r(r),c(c),type(type) {};
};
Cam c[8]; //최대 8개의 카메라
vector<int> v; //카메라 방향
int dr[] = { -1,0,1,0 }, dc[] = { 0,1,0,-1 }; //상우하좌
int N, M, C;//카메라의 개수
int map[8][8];
int back[8][8];
int ans = 1e9;
//정해진 방향으로 쭉 보기
void solve1(int r,int c,int dir) {
int nr=r, nc=c;
while (1) {
nr += dr[dir], nc += dc[dir];
if (nr >= 0 && nc >= 0 && nr < N && nc < M && map[nr][nc] != 6) {
back[nr][nc] = 8;//봤다 표시
}
else break;
}
}
void dfs(int len) {
if (len == C) {
//back에 map을 복사함
memcpy(back, map, sizeof(back));
//카메라 타입과 방향에 대해서 시뮬레이션을 돌림.
for (int i = 0; i < C; i++) {
int t = c[i].type, dir = v[i];
int rr = c[i].r, cc = c[i].c;
if (t == 1) solve1(rr, cc, dir);
else if (t == 2) {
if (dir == 0) { solve1(rr, cc, 0); solve1(rr, cc, 2); }
else if (dir == 1) { solve1(rr, cc, 1); solve1(rr, cc, 3); }
}
else if (t == 3) {
if (dir == 0) { solve1(rr, cc, 0); solve1(rr, cc, 1);}
else if (dir == 1) { solve1(rr, cc, 1); solve1(rr, cc, 2); }
else if (dir == 2) { solve1(rr, cc, 2); solve1(rr, cc, 3); }
else if (dir == 3) { solve1(rr, cc, 0); solve1(rr, cc, 3); }
}
else if (t == 4) {
if (dir == 0) { solve1(rr, cc, 0); solve1(rr, cc, 1); solve1(rr, cc, 3); }
else if (dir == 1) { solve1(rr, cc, 0); solve1(rr, cc, 1); solve1(rr, cc, 2); }
else if (dir == 2) { solve1(rr, cc, 1); solve1(rr, cc, 2); solve1(rr, cc, 3); }
else if (dir == 3) { solve1(rr, cc, 0); solve1(rr, cc, 2); solve1(rr, cc, 3); }
}
else if (t == 5) { solve1(rr, cc, 0); solve1(rr, cc, 2); solve1(rr, cc, 1); solve1(rr, cc, 3); }
}
//최소값 체크
int cnt = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (back[i][j] == 0) cnt++;
}
}
if (ans >= cnt) ans = cnt;
return;
}
//방향에 대한 순열을 만들어준다... 카메라 타입에 따라 약간 다르다
//시작이 계속 0이고, 방문체크도 안하므로 순열이다.
//방문한것 체크해서 안해주면 중복X순열이다
//시작을 하나씩 늘려가며 해주면 조합이다.
if (c[len].type == 1 || c[len].type == 3 || c[len].type == 4) {
for (int i = 0; i < 4; i++) {
v.push_back(i);
dfs(len + 1);
v.pop_back();
}
}
else if (c[len].type == 2) {
for (int i = 0; i < 2; i++) {
v.push_back(i); //0이면 상하 , 1이면 좌우
dfs(len + 1);
v.pop_back();
}
}
else if (c[len].type == 5) {
v.push_back(1); //1이면 상하좌우
dfs(len + 1);
v.pop_back();
}
}
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] != 0 && map[i][j] != 6) { c[C] = Cam(i, j, map[i][j]); C++; }
}
}
dfs(0);
printf("%d\n", ans);
return 0;
}
|
cs |
'알고리즘 > 그리디&완탐' 카테고리의 다른 글
[백준]색종이 붙이기 (1) | 2019.08.06 |
---|---|
[백준]스타트링크(두번째) (0) | 2019.08.02 |
[백준]30_그리디?정수론? (0) | 2019.06.30 |
[백준]로프 (0) | 2019.06.30 |
[백준]거스름돈 (0) | 2019.06.30 |