https://www.acmicpc.net/problem/17135
궁수 세 명을 최적의 위치에 배치해서, 가장 많은 적을 죽이도록 하는 문제이다.
따라서 열의 길이를 이용해서, 궁수가 위치할 수 있는 세 곳을 먼저 조합으로 뽑는다.
각각의 궁수에 대해 bfs를 돌린다. 앞에서부터 멀리있는 곳까지 확인할 것이다.
이때 중요한 것이 몇가지 있다.
궁수들은 같은 거리라면 왼쪽에 있는 적부터 공격한다. 따라서 bfs를 수행할 때, 탐색의 순서를 좌, 상, 우 이렇게 해줘야 한다.
또한 궁수들은 동시에 같은 적을 공격할 수 있다고 했기 때문에, 하나의 궁수를 가지고 탐색을 하다가 적을 발견했을 때에, 바로 그 적을 없애면 안 된다.
그걸 없애버리면 동시에 같은 적을 공격할 수 있다는 조건에 위배되기 때문이다.
set에 추가만 해주고, 이번 턴에 죽일 적을 찾았으므로, 바로 현재 궁수의 bfs를 종료해주면 된다.
세 궁수의 탐색이 사정거리만큼 모두 이루어지고 나면 set을 활용해서 지도에서 적을 지우고, set을 비워준다.
시기적절하게 초기화를 해주고, 적들을 지도에서 제거하고, 적들을 이동시키는 잔처리가 중요한 문제였다.
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 | #include<iostream> #include<queue> #include<set> using namespace std; typedef pair<int, int> pii; int m[19][18], tmp[19][18], N, M, d, st = 1, arr[19], dis[19][18]; int dr[3] = { 0,-1,0 }, dc[3] = {-1, 0, 1}; bool isused[18]; queue<pii> q; set<pii> killed; void bfs(pii start) { dis[start.first][start.second]++; q.push(start); while (!q.empty()) { pii cur = q.front(); q.pop(); if (dis[cur.first][cur.second] >= d) continue; //사정거리 마지막 점 for (int i = 0; i < 3; i++) { int nr = cur.first + dr[i]; int nc = cur.second + dc[i]; if (nr < 1 || nc < 1 || nr > N || nc > M || dis[nr][nc] >= 0) continue; if (m[nr][nc] == 1) { killed.insert({ nr, nc }); return; } q.push({ nr, nc }); dis[nr][nc] = dis[cur.first][cur.second] + 1; } } } void init() { for(int i = 1 ; i <= N+1 ; i++) for(int j = 1 ; j <= M ; j++) dis[i][j] = -1; while (!q.empty()) q.pop(); } bool allKilled() { for (int i = 1; i <= N; i++) for (int j = 1; j <= M; j++) if (m[i][j] != 0) return false; return true; } int kill() { int cnt = 0; for (set<pii>::iterator itr = killed.begin(); itr != killed.end(); itr++) { m[itr->first][itr->second] = 0; cnt++; } killed.clear(); return cnt; } void move() { for (int i = N; i >= 1; i--) for (int j = 1; j <= M; j++) m[i][j] = m[i - 1][j]; } int ans = 0; void btk(int k) { if (k == 3) { int killSum = 0; while (1) { //적 다 사라질 때까지 if (allKilled()) break; for (int i = 0; i < 3; i++) { bfs({ N + 1, arr[i] }); init(); } killSum += kill();//죽은 적들 배열에서 제거 move(); } if (ans < killSum) ans = killSum; for (int i = 1; i <= N; i++) for (int j = 1; j <= M; j++) m[i][j] = tmp[i][j]; return; } if (k == 0) st = 1; for (int i = st; i <= M; i++) { if (!isused[i]) { arr[k] = i; st = i; isused[i] = true; btk(k + 1); isused[i] = false; } } } int main(void) { cin >> N >> M >> d; for (int i = 1; i <= N; i++) { for (int j = 1; j <= M; j++) { cin >> m[i][j]; tmp[i][j] = m[i][j]; } } btk(0); cout << ans; return 0; } | cs |
'알고리즘 문제 풀이 > 백준 온라인 저지' 카테고리의 다른 글
백준 15684번: 사다리 조작 (C++) (0) | 2019.08.23 |
---|---|
백준 16637번: 괄호 추가하기 (C++) (0) | 2019.08.21 |
백준 17406번: 배열돌리기4 (C++) (0) | 2019.08.20 |
백준 11053번 가장 긴 증가하는 부분 수열 (C++) (0) | 2019.08.19 |
백준 1926번 그림 (C++) (0) | 2019.08.19 |