ps/알고리즘

코드트리 - 왕실의 기사 대결

nastorond 2024. 10. 9. 21:32

왕실의 기사 대결

코드트리 Gold 3 Simulation BFS
코드트리 - 왕실의 기사 대결

 

코드트리 | 코딩테스트 준비를 위한 알고리즘 정석

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

 

문제 풀이

마법의 숲 탐색에서 했던 방식처럼 테두리에 패딩을 둬 바운더리를 체크하지 않아도 되도록 했다.

기사가 명령을 받아 움직이기 시작할 때, 필드에 있는 기사끼리의 상호작용이 핵심인 문제였다.
기사가 밀쳐졌을 경우, 이동해야 하는 위치에 벽이 있다면 전체 상호작용이 없던 셈 쳐지고, 해당 턴이 사라지는 것과 같은 효과가 있었다.


이를 해결하기 위해 여러 방법을 시도해 봤지만, 쉽지 않았고 답을 확인했었는데,
그냥 필드를 복사해서 두번 체크해보면 되는 것 이었다.

주어지는 필드의 크기가 그렇게 크지 않고, 명령의 수가 최대 100개만 주어지기 때문에, 한 명령을 두번씩 시행한다고 생각해도 시간적으로 빡빡하지 않았었다.


이런식으로 생각해본적이 없어서 좀 오래 해맸던 것 같다.

코드

#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
#include <unordered_set>

using namespace std;

struct nightInfo {
    int x, y, health, maxHP, width, height;
    bool isLive;

    nightInfo () : x(0), y(0), maxHP(0), health(0), width(0), height(0), isLive(true) {}
};

vector<vector<int>> fld;
unordered_map<int, nightInfo> nights;
int mv[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};

bool tryIsAvail (int num, int& dir) {
    vector<vector<int>> fld2 = fld;
    queue<int> q;
    unordered_set<int> ck;

    q.push(num);
    ck.insert(num);

    while (!q.empty()) {
        num = q.front(); q.pop();
        int x = nights[num].x;
        int y = nights[num].y;
        for (int i=x; i<x+nights[num].height; i++) {
            for (int j=y; j<y+nights[num].width; j++) {

                int dx = i + mv[dir][0];
                int dy = j + mv[dir][1];
                fld2[i][j] -= num;
                int tmp = fld2[dx][dy]%2 ? fld2[dx][dy]-1 : fld2[dx][dy];

                if (fld2[dx][dy] == 2) return false;
                if (fld2[dx][dy] > 3 && ck.count(tmp) == 0) {
                    ck.insert(tmp);
                    q.push(tmp);
                }

                fld2[dx][dy] += num;
            }
        }
    }
    return true;
}

void simulation(int num, int& dir) {
    if (!tryIsAvail(num, dir)) return ;

    queue<int> q;
    unordered_set<int> ck;

    q.push(num);
    ck.insert(num);

    while (!q.empty()) {
        int nightNum = q.front(); q.pop();
        int x = nights[nightNum].x;
        int y = nights[nightNum].y;
        int cnt = 0;
        nights[nightNum].x += mv[dir][0];
        nights[nightNum].y += mv[dir][1];

        for (int i=x; i<x+nights[nightNum].height; i++) {
            for (int j=y; j<y+nights[nightNum].width; j++) {
                int dx = i + mv[dir][0];
                int dy = j + mv[dir][1];
                fld[i][j] -= nightNum;
                int tmp = fld[dx][dy]%2 ? fld[dx][dy]-1 : fld[dx][dy];
                if (fld[dx][dy] > 3 && ck.count(tmp) == 0) {
                    ck.insert(tmp);
                    q.push(tmp);
                }
                fld[dx][dy] += nightNum;
                if (fld[dx][dy]%2) cnt++;
            }
        }
        if (nightNum == num) continue;
        nights[nightNum].health -= cnt;
        if (nights[nightNum].health <= 0) {
            nights[nightNum].isLive = false;
            for (int i=nights[nightNum].x; i<nights[nightNum].x+nights[nightNum].height; i++) {
                for (int j=nights[nightNum].y; j<nights[nightNum].y+nights[nightNum].width; j++) fld[i][j] -= nightNum;
            }
        }
    }

    return ;
}

int main() {
    ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    int L, N, Q, res=0;

    cin >> L >> N >> Q;
    fld.resize(L+2, vector<int>(L+2, 2));

    for (int i=1; i<=L; i++) {
        for (int j=1; j<=L; j++) {
            cin >> fld[i][j];
        }
    }

    for (int i=2; i<=N+1; i++) {
        nightInfo tmp;
        cin >> tmp.x >> tmp.y >> tmp.height >> tmp.width >> tmp.health;
        tmp.maxHP = tmp.health;
        for (int h=tmp.x; h<tmp.x+tmp.height; h++) {
            for (int w=tmp.y; w<tmp.y+tmp.width; w++) {
                fld[h][w] += i*2;
            }
        }
        nights[i*2] = tmp;
    }

    for (int q=0; q<Q; q++) {
        int i, d;
        cin >> i >> d;
        if (!nights[i*2+2].isLive) continue;

        simulation(i*2+2, d);
    }

    for (auto night : nights) {
        if (!night.second.isLive) continue;
        res += night.second.maxHP - night.second.health;
    }

    cout << res << "\n";

    return 0;
}

후기

점점 디버깅이 안될 때 어떻게 대처해야할 지 방법들을 하나하나 모으고 있는 것 같다.


주어진 필드에 패딩을 주거나, 같은 작업을 두번 반복 한다거나 하는 것 같은..