[백준]18809_Gaaaaaaaaaarden(java)

2024. 10. 30. 17:51알고리즘 풀이

https://www.acmicpc.net/problem/18809

 

문제 설명
빨간색 배양액과 초록색 배양액 두개를 정해진 개수를 모두 땅에 뿌렸을 때(노란색땅에만 뿌리기 가능)
두 배양액은 계속 퍼진다. 퍼지다가 동시에 서로 다른 배양액이 어떤 위치에서 만나면 꽃이 피고, 꽃은 퍼지지않음.
필 수 있는 꽃의 최대 개수를 구하자.

입력값 
호수 : 0
땅 : 1
배양액 뿌릴 수 있는 땅 : 2

풀이
1. 모든 배양액을 뿌릴 수 있는 모든 경우를 고려한다.(DFS)
2. 뿌려진 배양액 정보를 가지고 꽃이 몇개 피우는지 시뮬레이션한다.(BFS)
BFS에서 빨간액은 4 초록액은 3으로 값을 설정하고 이동하다가 같은 시간대에 7(3+4)이 되면 꽃의 개수를 증가시킨다.
큐에서 뽑은 값이 꽃이 된거라면 그 경우 제외한다.

전체코드

package BJ;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

/**
 * 1. 배양액을 뿌릴 수 있는 모든 경우를 따져봐서 뿌려본다.
 * 2. 배양액을 모두 뿌렸을 때 bfs를 사용해서 시뮬레이션을 돌려보고, 꽃의 개수를 찾아 리턴한다.
 * 3. 리턴받은 꽃의 개수의 최대값을 갱신한다.
 */
public class BJ_18809_Garden {
    static int N, M, R, G, ans;
    static final int RED = 3, GREEN = 4, TWO = 2;
    static ArrayList<int[]> li;
    static int[][] garden;

    public static void main(String[] args) throws IOException {
        ans = 0;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        li = new ArrayList<>();

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        G = Integer.parseInt(st.nextToken());
        R = Integer.parseInt(st.nextToken());

        garden = new int[N][M];

        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < M; j++) {
                garden[i][j] = Integer.parseInt(st.nextToken());
                if (garden[i][j] == TWO) li.add(new int[]{i, j}); // 배양액 뿌릴 수 있는 위치 기록.
            }
        }

        // 가능한 모든 경우에 배양액 뿌려보기.
        back(0, G, R);
        System.out.println(ans);
    }

    private static void back(int cnt, int g, int r) {
        // 배양액을 둘 수 있는 위치에 모두 두었고, 각 색의 배양액을 모두 놓은 상황이라면.
        if (cnt == li.size()) {
            if (g == 0 && r == 0) {
//                showGarden(garden, "빽트결과");
                ans = Math.max(ans, bfs());
//                System.out.println("현재 최대 : "+ans);
            }
            return;
        }

        int[] cur = li.get(cnt);
        int ci = cur[0], cj = cur[1];
        // 초록 배양액을 놓는 경우
        if (g > 0) {
            garden[ci][cj] = GREEN;
            back(cnt + 1, g - 1, r);
        }
        if (r > 0) {
            garden[ci][cj] = RED;
            back(cnt + 1, g, r - 1);
        }
        garden[ci][cj] = TWO;
        back(cnt + 1, g, r);
        // 빨간 배양액을 놓는 경우
        // 되돌리기.

    }

    private static void showGarden(int[][] map, String des) {
        System.out.println("-------------" + des + "------------");
        for (int[] ints : map) {
            System.out.println(Arrays.toString(ints));
        }
    }

    private static int bfs() {
        int[] di = {-1, 1, 0, 0}, dj = {0, 0, -1, 1}; // 상하좌우.
        int cnt = 0, time = 1; // 꽃개수와 현재 시간.
        Queue<Info> q = initQ(); // 배양액이 뿌려져있는 곳 위치정보 받아옴.
        int[][] v = new int[N][M]; // 시간을 기록할것.
        int[][] tmp = copyGarden(); // 정원을 기록할것.

        // 색깔별로 정원에 퍼진 배양액 기록하기

        for (int i = 0; i < q.size(); i++) { // 현재 배양액 뿌린곳 방문체크.
            Info cur = q.poll();
            v[cur.ci][cur.cj] = -1;
            tmp[cur.ci][cur.cj] = cur.color; // 정원에 씨앗 뿌려
            q.offer(cur);
        }


        
        while (!q.isEmpty()) {

            Info cur = q.poll(); // 현재 위치
            int ci = cur.ci, cj = cur.cj;
            if (tmp[ci][cj] >= RED + GREEN) continue; // 현 위치가 꽃이면 더이상 퍼지지않게한다.

            for (int dir = 0; dir < 4; dir++) { // 4방향으로 퍼질 수 있는 곳을 찾기.
                int ni = ci + di[dir];
                int nj = cj + dj[dir];

                // 범위내, 이동할 위치가 처음이거나 같은 시간대에 이동한거면, && 호수가 아니면!
                if (isIn(ni, nj) && (v[ni][nj] == 0 || v[ni][nj] == cur.time + 1) && tmp[ni][nj] != 0) {
                    // 이미 같은 종류의 배양액이 있는경우 넘어가자~
                    if (tmp[ni][nj] == cur.color) continue;

                    v[ni][nj] = cur.time + 1; // 이동하는데 1초가 걸린다.

                    if (tmp[ni][nj] == 1 || tmp[ni][nj] == 2) { // 이동 가능한 위치라면 이동
                        tmp[ni][nj] = cur.color;    // 값을 배양액 색으로 대입하기.
                    } else { // 다른 배양액이 들어와있다면, 더해서 꽃을 만들자.
                        tmp[ni][nj] += cur.color;
                    }

                    if (tmp[ni][nj] == RED + GREEN) { // 꽃이 피었을 때 개수 증가.
                        cnt++;
                    } else { // 꽃이 아니면 다음에 또 퍼지도록
                        q.offer(new Info(ni, nj, cur.time + 1, cur.color));
                    }
                }
            }


        }

//        showGarden(tmp,"tmp");
        return cnt; // 꽃 개수 리턴 
    }
	// 맵 복사.
    private static int[][] copyGarden() {
        int[][] r = new int[N][M];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                r[i][j] = garden[i][j];
            }
        }
        return r;
    }
    
	// dfs에서 뿌려진 배양액들 정보 큐로 넘겨주기.
    private static Queue<Info> initQ() {
        Queue<Info> q = new LinkedList<>();
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (garden[i][j] == RED || garden[i][j] == GREEN) {
                    q.offer(new Info(i, j, 1, garden[i][j]));
                }
            }
        }
        return q;
    }
	// 범위내 체크 
    private static boolean isIn(int ni, int nj) {
        return 0 <= ni && ni < N && 0 <= nj && nj < M;
    }

    private static class Info {
        int ci, cj, time, color; // 배양액 위치, 시간, 색깔

        public Info(int ci, int cj, int time, int color) {
            this.ci = ci;
            this.cj = cj;
            this.time = time;
            this.color = color;
        }
    }
}

'알고리즘 풀이' 카테고리의 다른 글

[백준]17071_숨바꼭질5  (2) 2024.11.02
[백준]6549_히스토그램에서 가장 큰 직사각형  (1) 2024.10.30
[백준]17298_오큰수  (2) 2024.10.14
[백준]BJ_9202_Boggle  (2) 2024.09.20
Softeer_LV3_나무섭지  (2) 2024.09.09