본문 바로가기

알고리즘/백준

백준 18809 Gaaaaarden

728x90

 

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

 

18809번: Gaaaaaaaaaarden

첫째 줄에 정원의 행의 개수와 열의 개수를 나타내는 N(2 ≤ N ≤ 50)과 M(2 ≤ M ≤ 50), 그리고 초록색 배양액의 개수 G(1 ≤ G ≤ 5)와 빨간색 배양액의 개수 R(1 ≤ R ≤ 5)이 한 칸의 빈칸을 사이에 두고 주어진다. 그 다음 N개의 줄에는 각 줄마다 정원의 각 행을 나타내는 M개의 정수가 한 개의 빈 칸을 사이에 두고 주어진다. 각 칸에 들어가는 값은 0, 1, 2이다. 0은 호수, 1은 배양액을 뿌릴 수 없는 땅, 2는 배양

www.acmicpc.net

전형적인 삼성 역량테스트에서 나올법한 문제

 

너무 친절하게 테스트케이스를 다 줘서 생각보다 쉽게 풀었던 문제이다.

 

삼성 역테 준비하는 사람이면 시간 맞춰놓고 1시간안에 풀기 연습 하면 괜찮을듯

 

※ 풀이과정

1. 땅의 조합 찾기(DFS)

 

n : 땅갯수 g : 초록색 갯수 r : 빨간색 갯수

1) 초록색 배양할 땅고르기 (DFS) nCg

2) 빨간색 배양할 땅고르기 (DFS) n-gCr

3) 전체 가짓수 nCg * n-gCr 

 

여기서 주의할 점은 n>=(g+r)이라는 점 즉 조합을 2번에 걸쳐서 구해야한다.

 

2. 시뮬레이션 돌리기(BFS)

1) 앞의 1번에서 구한 조합으로 시뮬레이션을 돌리고 시뮬레이션 한 값의 최대값을 구한다.

2) 당연히 map 값이 1이거나 2인 지점만 방문가능하다. (호수인 지점이나 초록색 빨간색이 이미 그전에 뿌려진 점도 방문불가능)

3) 주의할점은 초록색과 빨간색이 "동시에 만나는 지점에서만 꽃이 핀다는점" 나 같은경우에는 초록색을 먼저 bfs 돌리고 방문 가능한점들을 map의 값을 -1로 바꿨고, 그 후 빨간색에서 BFS을 돌렸을때 map의 값이 -1인 지점을 방문하면 꽃이 핀다고 카운트 했음(당연히 카운트하자마자 -1을 다른값으로 바꿔야된다 아니면 중복되서 카운트 된다.)

 

package 백준;

import java.io.*;
import java.util.*;

public class Garden {
	static class MyScanner {
		BufferedReader bf;
		StringTokenizer st;

		MyScanner() {

			bf = new BufferedReader(new InputStreamReader(System.in));

		}

		String next() {

			while (st == null || !st.hasMoreTokens()) {
				try {
					st = new StringTokenizer(bf.readLine());
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
			return st.nextToken();

		}

		int nextInt() {
			return Integer.parseInt(next());

		}

	}

	static int N, M, G, R;
	static int map[][];
	static int answer = 0;
	static Point gal[];
	static Point ral[];
	static int dx[] = { -1, 1, 0, 0 };
	static int dy[] = { 0, 0, -1, 1 };

	static class Point {
		int x;
		int y;
		char color;
		int time;

		Point(int x, int y, char val, int time) {
			this.x = x;
			this.y = y;
			this.color = val;
			this.time = time;
		}
	}

	static void rspread(int idx, int rcnt) {

		if (rcnt < R) {
			for (int i = idx; i < pc; i++) {
				if (map[pland[i].x][pland[i].y] != 2)
					continue;
				map[pland[i].x][pland[i].y] = 4;
				rspread(i + 1, rcnt + 1);
				map[pland[i].x][pland[i].y] = 2;
			}
		} else {
			int partial_answer = bfs();

			ddd++;
			answer = Math.max(answer, partial_answer);
			return;
		}
	}

	static void gspread(int idx, int gcnt) {

		if (gcnt < G) {
			for (int i = idx; i < pc; i++) {
				map[pland[i].x][pland[i].y] = 3;
				gspread(i + 1, gcnt + 1);
				map[pland[i].x][pland[i].y] = 2;

			}
		} else {

			ccc++;
			rspread(0, 0);

		}

	}

	static void print_map(int map[][]) {
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				System.out.printf(map[i][j] + " ");
			}
			System.out.println();
		}
		System.out.println();
	}

	static Point pland[];
	static int pc;
	static int ddd;
	static int ccc;
	
	static int bfs() {

		Queue<Point> gq = new LinkedList<Point>();
		Queue<Point> rq = new LinkedList<Point>();
		int pa = 0;
		int temp[][] = new int[N][M];
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				temp[i][j] = map[i][j];
			}
		}
	
		for (int i = 0; i < pc; i++) {
			if (temp[pland[i].x][pland[i].y] == 3)
				gq.add(new Point(pland[i].x, pland[i].y, 'g', 0));// 초록색 큐
			if (temp[pland[i].x][pland[i].y] == 4)
				rq.add(new Point(pland[i].x, pland[i].y, 'r', 0));// 빨간색 큐
		}

		while (!gq.isEmpty() || !rq.isEmpty()) {

			int gs = gq.size();
			int rs = rq.size();
			ArrayList<Point> tq = new ArrayList<Point>();
			for (int i = 0; i < gs; i++) {

				Point g = gq.poll();
				for (int j = 0; j < 4; j++) {
					int nx = g.x + dx[j];
					int ny = g.y + dy[j];
					int nt = g.time + 1;
					if (nx < 0 || ny < 0 || nx >= N || ny >= M)
						continue;

					if (temp[nx][ny] != 1 && temp[nx][ny] != 2)
						continue;
					tq.add(new Point(nx, ny, 'g', nt));
					temp[nx][ny] = -1; // g가 퍼진땅 동시 체크 위함
				}
			}
			for (int i = 0; i < rs; i++) {

				Point r = rq.poll();
				for (int j = 0; j < 4; j++) {
					int nx = r.x + dx[j];
					int ny = r.y + dy[j];
					int nt = r.time + 1;
					if (nx < 0 || ny < 0 || nx >= N || ny >= M)
						continue;
					if (temp[nx][ny] == -1) {
						temp[nx][ny] = 7; // g가 퍼진땅 동시 체크 위함
						pa++;
					}
					if (temp[nx][ny] != 1 && temp[nx][ny] != 2)
						continue;
					temp[nx][ny] = -2; // g가 퍼진땅 동시 체크 위함
					tq.add(new Point(nx, ny, 'r', nt));

				}
			}
			for (Point p : tq) {
				if (temp[p.x][p.y] == -1) {
					temp[p.x][p.y] = 3;
					gq.add(p);
				}
				if (temp[p.x][p.y] == -2) {
					temp[p.x][p.y] = 4;
					rq.add(p);d
				}

			}

		}

		return pa;
	}

	public static void main(String[] args) {
		MyScanner sc = new MyScanner();
		N = sc.nextInt();
		M = sc.nextInt();
		G = sc.nextInt();
		R = sc.nextInt();

		map = new int[N][M];
		pland = new Point[11];
		
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				map[i][j] = sc.nextInt();
				if (map[i][j] == 2) {
					pland[pc++] = new Point(i, j, 'p', 0);
				}
			}
		}
		gal = new Point[G];
		ral = new Point[R];
		gspread(0, 0);

		System.out.println(answer);
	}

}

'알고리즘 > 백준' 카테고리의 다른 글

백준 1669멍멍이 쓰다듬기  (0) 2020.04.23
백준 18808 스티커 붙이기  (0) 2020.04.19
백준 2931 가스관  (0) 2020.04.15
백준 12784 인하니카 공화국  (0) 2020.04.14
백준 2831 댄스파티  (0) 2020.04.10