알고리즘||코딩테스트/BFS

[BOJ 2251] 물통 - JAVA, Gold5

째로스 2023. 9. 4. 22:15

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

 

2251번: 물통

각각 부피가 A, B, C(1≤A, B, C≤200) 리터인 세 개의 물통이 있다. 처음에는 앞의 두 물통은 비어 있고, 세 번째 물통은 가득(C 리터) 차 있다. 이제 어떤 물통에 들어있는 물을 다른 물통으로 쏟아 부

www.acmicpc.net

사용한 알고리즘 : BFS

 

풀이전략

 

모든 경우의 수를 BFS를 사용해 완전탐색하는 문제이다.

 

물통에서 물을 옮길 수 있는 경우의 수는 총 6가지로,

1. A물통-> B물통

2. A물통-> C물통

3. B물통 -> A물통

4. B물통 -> C물통

5. C물통 -> A물통

6. C물통 -> B물통

이 있다.

 

그런데 물을 옮길 때 조건으로

한 물통이 빌 때까지 물을 다른 물통에 쏟거나, 다른 물통이 가득찰 때까지 부어야 한다.

 

그렇기 때문에 물통 A에 물이 x리터있고 물통 B에 물이 y리터 있을 때

물통 A에서 물통 B로 물을 쏟아부을 수 있는 부피는 Math.min(x,B-y)이다.

 

이유는 아래 그림과 같이 x>B-y이면

A물통의 물 x리터를 B로 모두 다 옮길 수 없어 B-y리터만 옮길 수 있기 때문이다. 

 

반대로 x<=B-y이면

물통 A의 모든 물 x리터를 물통 B로 옮길 수 있어 Math.min(x,B-y) 만큼의 물을 이동시킬 수 있는 것이다. 

물론 이는 A물통->B물통으로 물을 옮길 때만의 수식이었고,

다른 경우의 모든 수식을 각자 작성해 BFS 알고리즘을 완성시키면 된다.

 

그 과정 속에서 visited 이중 배열을 사용하여 (x,y) 경우의 수에 대한 중복을 방지하고

 

x=0인 경우, z=C-x-y 값을 저장해둔다.

 

그리고 BFS 탐색이 끝나면 z로 나올 수 있는 저장해둔 모든 경우의 수를 오름차순으로 출력하면 된다.

(나는 TreeSet을 사용하여 중복되지않으면서 오름차순으로 출력되도록 하였다.)

 

 

제출코드

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

public class Main {
    static int A,B,C;
    static class Node{
        int x;
        int y;
        int z;

        public Node(int x, int y, int z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }
    }
    static boolean visited[][];
    static TreeSet<Integer> set = new TreeSet<>();

    static boolean pour(int x,int y){
        if(!visited[x][y]){
            visited[x][y]=true;
            return true;
        }
        return false;
    }

    static void bfs(){
        Queue<Node> q = new LinkedList<>();
        q.offer(new Node(0,0,C));
        visited[0][0]=true;

        while(!q.isEmpty()){
            Node now = q.poll();

            if(now.x==0){
                set.add(now.z);
            }

            // x->y
            int water = Math.min(now.x,B-now.y);
            if(pour(now.x-water,now.y+water)){
                q.offer(new Node(now.x-water,now.y+water,C-(now.x-water)-(now.y+water)));
            }

            // x->z
            water = Math.min(now.x,C-now.z);
            if(pour(now.x-water,now.y)){
                q.offer(new Node(now.x-water,now.y,now.z+water));
            }

            // y->x
            water = Math.min(now.y,A-now.x);
            if(pour(now.x+water,now.y-water)){
                q.offer(new Node(now.x+water,now.y-water,C-(now.x+water)-(now.y-water)));
            }

            // y->z
            water = Math.min(now.y,C-now.z);
            if(pour(now.x, now.y-water)){
                q.offer(new Node(now.x, now.y-water,C-now.x-(now.y-water)));
            }

            // z->x
            water = Math.min(now.z,A-now.x);
            if(pour(now.x+water,now.y)){
                q.offer(new Node(now.x+water,now.y,C-(now.x+water)-now.y));
            }

            // z->y
            water = Math.min(now.z,B-now.y);
            if(pour(now.x,now.y+water)){
                q.offer(new Node(now.x,now.y+water,C-now.x-(now.y+water)));
            }
        }
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        A = Integer.parseInt(st.nextToken());
        B = Integer.parseInt(st.nextToken());
        C = Integer.parseInt(st.nextToken());

        visited = new boolean[A+1][B+1];

        bfs();

        for(int x:set){
            bw.write(x+" ");
        }
        bw.write("\n");
        bw.flush();
        bw.close();
    }
}