[BOJ][サムスン基出]16236小さなサメ


質問へのアクセス

  • が食べられる魚探索がポイントです.(get_target())
  • まずすべての魚に対してサメとの距離を求める.
  • 以降食べられる魚があれば魚の情報を返します.
    まずすべての魚の距離を-1にします。 到達可能な魚の距離をbfsで更新します。 もし、update後のすべての魚とサメの距離が-1であれば、-1に戻ります。魚が食べられないからです。(魚が食べられるかどうかを探る) 1匹以上の距離が-1でない場合は、最も距離の小さい魚を食べます。 複数の魚が最短距離にある場合、vectorで最初に探索された魚は、問題で定義された優先度に合致する。(入力時にvectorを順番に入れます。入力は左上からです。)
  • の他の人の説から見ると、彼らは食べ物構造体に生命変数を使用していない.(昔の私も)
    しかし、問題を解くとき、私が作った論理は整理されました.
    次回はコメントしておけばよかったです.
  • に答える

    #include <iostream>
    #include <queue>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef struct food {
        int x;
        int y;
        int size;
        int d;
        bool life;
    } food;
    
    int N, M, rst, cnt, sx, sy, s_size;
    int map[20][20];
    vector <food> F;
    int dx[] = { 0, 1, 0, -1 };
    int dy[] = { 1, 0, -1, 0 };
    
    void input() {
        cin >> N;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                cin >> map[i][j];
                if (map[i][j] > 0 && map[i][j] < 9) {
                    food f;
                    f.x = i; f.y = j; f.size = map[i][j]; f.d = 0; f.life = true;
                    F.push_back(f);
                }
                else if (map[i][j] == 9) {
                    sx = i; sy = j; s_size = 2;
                }
            }
        }
        rst = 0; cnt = 0;
    }
    
    void get_target(int ret) {
        rst += F[ret].d;
        map[sx][sy] = 0;
        sx = F[ret].x;
        sy = F[ret].y;
        F[ret].life = false;
        map[F[ret].x][F[ret].y] = 9;
    
        cnt++;
        if (s_size == cnt) {
            s_size++;
            cnt = 0;
        }
    }
    
    int is_range(int x, int y) {
        if (x >= 0 && x < N && y >= 0 && y < N) return true;
        return false;
    }
    
    int find_target() {
        int is_visit[20][20];
        memset(is_visit, 0, sizeof(is_visit));
        queue <pair<pair<int, int>, int>> Q;
        
        Q.push(make_pair(make_pair(sx, sy), 0));
        is_visit[sx][sy] = 1;
    
        for (int i = 0; i < F.size(); i++) {
            F[i].d = -1;
        }
        // 1. 모든 먹을 수 있는 물고기에 대해 상어와의 거리를 구한다.
        while (!Q.empty()) {
            int cx = Q.front().first.first;
            int cy = Q.front().first.second;
            int d = Q.front().second;
            Q.pop();
            // 현재 위치에 물고기가 있는지 확인
            for (int i = 0; i < F.size(); i++) {
                if (map[cx][cy] && cx == F[i].x && cy == F[i].y) {
                    if (map[cx][cy] < s_size) {
                        F[i].d = d;
                        break;
                    }
                }
            }
            for (int i = 0; i < 4; i++) {
                int nx = cx + dx[i];
                int ny = cy + dy[i];
                if (!is_visit[nx][ny] && is_range(nx, ny) && map[nx][ny] <= s_size) {
                    is_visit[nx][ny] = 1;
                    Q.push(make_pair(make_pair(nx, ny), d + 1));
                }
            }
        }
    
        // 2. 살아 있는 물고기 중 먹을 수 있는 물고기가 한 마리 이상 있는가?
        bool flag = false;
        for (int i = 0; i < F.size(); i++) {
            if (F[i].life && F[i].d != -1) flag = true;
        }
        if (!flag) return -1; // 없다면 종료
    
        //있다면 min distance를 구하고 min distance에 해당하는 물고기 중 가장 왼쪽에 위치한 물고기
        int m = 100000;
        for (int i = 0; i < F.size(); i++) {
            if (F[i].life && F[i].d != -1) m = min(m, F[i].d);
        }
    
        for (int i = 0; i < F.size(); i++) {
            if (F[i].life && F[i].d != -1) {
                if (F[i].d == m) return i;
            }
        }
    }
    
    void solve() {
        while(true) {
            int ret = find_target();
            if (ret == -1) {
                break;
            }
            get_target(ret);
        }
    }
    
    int main() {
        input();
        solve();
        cout << rst << endl;
    }