https://www.acmicpc.net/problem/16920
16920번: 확장 게임
구사과와 친구들이 확장 게임을 하려고 한다. 이 게임은 크기가 N×M인 격자판 위에서 진행되며, 각 칸은 비어있거나 막혀있다. 각 플레이어는 하나 이상의 성을 가지고 있고, 이 성도 격자판 위
www.acmicpc.net
코드설명
BFS(너비우선탐색) 를 활용하는 문제입니다.
문제에 대한 접근방식을 올바르게 접근해야합니다.
문제에서 가장 중요한점은, 각 이동방향을 "동시에" 처리해야하고, "동시에" 처리하기 위해서는 같은 이동사이클에서 다른 이동에 영향을 받지 않아야 합니다. 또한, 확장시 해당 범위 내에서 2칸의 모든 공간을 의미한다는점 또한 유의하여 각 이동을 처리해줍니다.
이를 위해 Queue[] 에서 처리하는것이라고 이해하면 도움이 될 것 입니다.
만약, PriorityQueue를 이용할경우 같은 이동사이클내에서 이동처리하는것이 불가합니다.
처음에 풀었던 코드는 PriorityQueue로 각 성의 숫자를 넣고서 BFS를 진행했습니다.
이떄 우선순위는 숫자가 낮을수록, 즉 1번성부터 움직이게 처리했습니다.
하지만, 이때 문제가 발생합니다.
각 성이 확장할때 성은 그 주변의 모든 거리 2에 해당하는 공간을 확장합니다.
문제에서는 직접적으로 그렇게 표현되어있지 않아, 입력예시 5번을 보고 깨닳았습니다.
(입력에시 5번이 이해 안갈경우, https://www.acmicpc.net/board/view/35314 )
또한 PriorityQueue를 사용하지않고, Queue[] 처리 방식으로 진행해야하는 이유는
https://www.acmicpc.net/board/view/35413
글 읽기 - 큐 처리 방식의 차이가 궁금합니다..ㅠ
댓글을 작성하려면 로그인해야 합니다.
www.acmicpc.net
위의 답변글을 보면 이해할 수 있습니다.
간단한 BFS 코드로직입니다.
- BFS() 메서드에서 각 사람의 이동을 BFS로 처리합니다.
- dx와 dy 배열은 상하좌우 이동을 나타냅니다.
- flag 변수는 모든 사람이 더 이상 이동할 수 없을 때까지 반복을 제어합니다.
- 이 부분에서 모든 Queue[] 를 확인하며 QSize가 0 이 하나도 없는경우로 처리해도되지만, 빠른 처리를 위해 flag로 한번도 Queue에 넣지 않는다면 종료시킵니다.
- while (!flag) 루프를 통해 모든 사람에 대한 BFS를 반복합니다.
코드
Queue[] 배열을 활용하여 진행합니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Stack;
import java.util.StringTokenizer;
public class Main {
public static int N, M, P;
public static char[][] map;
public static int[] S;
public static Queue<Node>[] q;
public static boolean[][] visited;
public static int[] answerCnt = new int[10];
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
P = Integer.parseInt(st.nextToken());
map = new char[N][M];
q = new Queue[P + 1];
for(int i=0;i<=P;i++) {
q[i] = new LinkedList<Node>();
}
st = new StringTokenizer(br.readLine());
S = new int[P+1];
for(int i=1;i<P+1;i++) {
S[i] = Integer.parseInt(st.nextToken());
}
visited = new boolean[N][M];
for(int i=0;i<N;i++) {
st = new StringTokenizer(br.readLine());
map[i] = st.nextToken().toCharArray();
for(int j=0;j<M;j++) {
if(map[i][j] >= '1' && map[i][j] <= '9') {
visited[i][j] = true;
q[map[i][j] - '0'].offer(new Node(i, j));
answerCnt[map[i][j] - '0'] += 1;
}
}
}
BFS();
for(int i=1; i<=P; i++) {
System.out.print(answerCnt[i]+" ");
}
}
public static void BFS() {
int[] dx = {-1,1,0,0};
int[] dy = {0,0,-1,1};
boolean flag = false;
while(!flag) {
flag = true;
for(int people=1; people<=P; people++) {
int moveCnt = S[people];
int qSize = q[people].size();
int cnt = 0;
int cycleCnt = 0;
while( !q[people].isEmpty() && cycleCnt < moveCnt) {
Node temp = q[ people].poll();
for(int dir = 0; dir < 4; dir++) {
int nr = temp.r + dx[dir];
int nc = temp.c + dy[dir];
if(nr < 0 || nr >= N || nc < 0 || nc >= M) continue;
if(visited[nr][nc] == true) continue;
if(map[nr][nc] == '#') continue;
visited[nr][nc] = true;
answerCnt[people] += 1;
flag = false;
q[people].offer(new Node(nr, nc));
}
cnt += 1;
if(qSize == cnt) {
qSize = q[people].size();
cnt = 0;
cycleCnt += 1;
}
}
//// System.out.println("========================");
// for(int i=0;i<=P;i++) {
// System.out.print(" "+answerCnt[i]);
// }
// System.out.println();
}
}
}
}
class Node{
int r;
int c;
public Node(int r, int c) {
this.r=r;
this.c=c;
}
}
PriorityQueue를 활용할경우, 먼저 탐색한 공간에 접근하지 못해 올바르게 확장되지 못합니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Stack;
import java.util.StringTokenizer;
public class Main {
public static int N, M, P;
public static char[][] map;
public static int[] S;
public static PriorityQueue<Node> pq = new PriorityQueue<>();
public static boolean[][] visited;
public static int[] answerCnt = new int[10];
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
P = Integer.parseInt(st.nextToken());
map = new char[N][M];
st = new StringTokenizer(br.readLine());
S = new int[P+1];
for(int i=1;i<P+1;i++) {
S[i] = Integer.parseInt(st.nextToken());
}
visited = new boolean[N][M];
for(int i=0;i<N;i++) {
st = new StringTokenizer(br.readLine());
map[i] = st.nextToken().toCharArray();
for(int j=0;j<M;j++) {
if(map[i][j] >= '1' && map[i][j] <= '9') {
visited[i][j] = true;
pq.offer(new Node(i, j, map[i][j] - '0'));
answerCnt[map[i][j] - '0'] += 1;
}
}
}
BFS();
for(int i=1; i<=P; i++) {
System.out.print(answerCnt[i]+" ");
}
}
public static void BFS() {
int[] dx = {-1,1,0,0};
int[] dy = {0,0,-1,1};
PriorityQueue<Node> newPq = new PriorityQueue<>();
int pqSize = pq.size();
int cnt = 0;
while(!pq.isEmpty()) {
Node temp = pq.poll();
// System.out.println("============");
// System.out.println(temp.r+" "+temp.c+" "+temp.idx);
for(int dir = 0; dir < 4; dir++) {
int moveCnt = S[temp.idx];
int nr = temp.r;
int nc = temp.c;
while(--moveCnt >= 0) {
nr += dx[dir];
nc += dy[dir];
if(nr < 0 || nr >= N || nc < 0 || nc >= M) break;
if(map[nr][nc] == '#') break;
if(visited[nr][nc] == true) break;
answerCnt[temp.idx] += 1;
visited[nr][nc] = true;
// System.out.println("nr:"+nr+ "nc:"+nc);
// pq.offer(new Node(nr, nc, temp.idx));
newPq.offer(new Node(nr, nc, temp.idx));
}
}
cnt += 1;
if(pqSize == cnt) {
pqSize = newPq.size();
cnt = 0;
pq = newPq;
newPq = new PriorityQueue<>();
}
}
}
}
class Node implements Comparable<Node>{
int r;
int c;
int idx;
public Node(int r, int c, int idx) {
this.r=r;
this.c=c;
this.idx=idx;
}
@Override
public int compareTo(Node other) {
if(this.idx > other.idx) {
return 1;
}else if(this.idx == other.idx){
return 0;
}else {
return -1;
}
}
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 4883 삼각 그래프 - 동적계획법(DP, Dynamic Programming) JAVA (0) | 2023.12.18 |
---|---|
[백준] 11967 불켜기 - BFS(너비우선탐색) JAVA (0) | 2023.12.17 |
[백준] 2750 숨바꼭질 4 - BFS(너비우선탐색) + 부모경로찾기(find Parent, LCA) JAVA (0) | 2023.12.16 |
[백준] 6593 상범 빌딩 - BFS(너비우선탐색, 3차원, Three Dimension) JAVA (0) | 2023.12.09 |
[백준] 5427 불 - BFS(너비우선탐색) + 구현(Implementation) JAVA (0) | 2023.12.08 |