[ 백준 ] 17135 / 캐슬 디펜스

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
30/228
post-thumbnail

# Appreciation

/*
 * Problem :: 17135 / 캐슬 디펜스
 *
 * Kind :: Simulation
 *
 * Insight
 * - 궁수 3명에 max(M)=15 이면
 *   15C3 = 455 정도 이고
 *   적이 격자판 가득하면
 *   다 내려오는데 O(N), 궁수가 공격할 적을 계산하는데
 *   모든 적을 한번씩 검사한다면 O(NM)
 *   외에 이러저러해도... O(N^2M) 정도일 듯 하다
 *   + 그래도 max(N,M)=15 이니
 *     시간제한 때문에 최적화 걱정없이 구현에만 집중하면 되겠다
 *
 * - 일단 궁수 위치선정은 next_permutation 으로 할까 하다가
 *   귀찮아서 3중 for 문으로 해결했다
 *   + 현재 격자판의 상태를 갱신하는 것으로 구현할까 싶었는데
 *     곰곰이 생각해보니 그냥 적의 좌표만 갱신시켜주면 된다
 *     # 궁수가 공격할 적의 좌표를 계산하는 것은
 *       결국 궁수와의 거리가 가장 가까운 적을 찾는 것이넫
 *       <algorithm> 의 min_element 함수를 이용하면 쉽게 구할 수 있을 것 같았다
 *       -> 공격할 적이 결정되면 이제 그 공격으로 적이 제거되어야 하는데
 *          Set 이 이와같은 과정에 적합한 자료구조라 생각했다
 *          (찾기도 쉽고, 제거도 쉬우니까)
 *          => 다만, Set 내부의 원소들은 const 로 건들 수가 없어서
 *             적들이 아래로 한칸 이동하는 것은
 *             새로운 임시의 Set 을 만들어서 해결했다
 *
 * Point
 * - class 로 Comparator 에 parameter 를 넘겨주기
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <set>
#include <algorithm>

using namespace std;

#define endl '\n'

// Set up : Global Variables
int N, M, D;
struct Point { int y, x; };
set<Point> E;

// Set up : Functions Declaration
bool operator < (const Point &u, const Point &v);
int tmp(int b1, int b2, int b3);
class Comp {
    int pos;
public:
    Comp(int b) { pos = b; }
    bool operator()(const Point &p1, const Point &p2) const;
};


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Set up : Input
    cin >> N >> M >> D;
    for (int i=0; i<N; i++) {
        for (int j=0; j<M; j++) {
            int v; cin >> v;
            if (v == 1) {
                E.insert({i, j}); /* 적의 좌표 저장 */
            }
        }
    }

    // Process
    int ans = -1;
    for (int b1=0; b1<M; b1++) { /* 궁수 1의 x 좌표 */
        for (int b2=b1+1; b2<M; b2++) { /* 궁수 2의 x 좌표 */
            for (int b3=b2+1; b3<M; b3++) { /* 궁수 3의 x 좌표 */
                ans = max(ans, tmp(b1, b2, b3));
            }
        }
    }

    // Control : Output
    cout << ans << endl;
}

// Helper Functions
bool operator < (const Point &u, const Point &v)
/* Point 구조체 비교를 위한 연산자 오버로딩 (set<Point> 로 활용하기 위함) */
{
    return make_pair(u.y, u.x) < make_pair(v.y, v.x);
}

bool Comp::operator()(const Point &p1, const Point &p2) const {
/* 궁수의 좌표 (N, pos) 로부터 가장 가까운 적의 좌표를
 * min_element 함수를 사용하여 구하기 위한 Comparator */
    int d1 = abs(p1.y-N) + abs(p1.x-pos);
    int d2 = abs(p2.y-N) + abs(p2.x-pos);
    return (d1 != d2) ? (d1 < d2) : (p1.x < p2.x);
}

int tmp(int b1, int b2, int b3)
/* 3명인 궁수들의 x 좌표인 b1, b2, b3 를 바탕으로 제거한 적의 최대 수를 반환 */
{
    set<Point> R = E;

    int cnt = 0; /* 제거한 적의 수 */
    while (not(R.empty())) {
        /* 궁수 1이 공격할 적의 좌표 */
        Point t1 = *min_element(R.begin(), R.end(), Comp(b1));
        int d1 = abs(t1.y-N) + abs(t1.x-b1); /* 궁수 1로부터 공격할 적의 좌표까지의 거리 */

        /* 궁수 2가 공격할 적의 좌표 */
        Point t2 = *min_element(R.begin(), R.end(), Comp(b2));
        int d2 = abs(t2.y-N) + abs(t2.x-b2); /* 궁수 2로부터 공격할 적의 좌표까지의 거리 */

        /* 궁수 3이 공격할 적의 좌표 */
        Point t3 = *min_element(R.begin(), R.end(), Comp(b3));
        int d3 = abs(t3.y-N) + abs(t3.x-b3); /* 궁수 3으로부터 공격할 적의 좌표까지의 거리 */

        /* 각 궁수로부터 공격할 적의 좌표까지의 거리가 D 이하이고 공격할 적이 제거되지 않았다면
         * 공격하여 적을 제거 */
        if (d1 <= D && (R.find(t1) != R.end())) { R.erase(t1), cnt++; }
        if (d2 <= D && (R.find(t2) != R.end())) { R.erase(t2), cnt++; }
        if (d3 <= D && (R.find(t3) != R.end())) { R.erase(t3), cnt++; }

        set<Point> T; /* 이동하고 남아있는 적의 좌표들 */
        for (auto p : R) {
            if (p.y+1 < N) {
                T.insert({p.y+1, p.x});
            }
        }

        R = T; /* 적들의 좌표 갱신 */
    }

    return cnt;
}
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글