알고리즘/백준

백준 2251 (물통) - java

김다미김태리신시아 2023. 1. 23. 15:41

 

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

 

2251번: 물통

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

www.acmicpc.net

* 크게 2가지 경우로 나눠볼 수 있다. A -> B의 경우를 생각해보자면 A 물통에 있는 모든 물을 B에 따를 수 있는 경우 , B의 물통이 그 전에 가득차 일부만 따르는 경우 

* 각 물통마다 2개의 물통에 따를 수 있기 때문에 6가지 경우의 수를 계산하여 BFS를 진행하면 된다.

* 참고로 HashSet에 결과를 저장하는 경우 정렬이 되는 것처럼 보이지만 기본적으로 정렬을 지원하지 않고 있다 ^^ !!!!

 

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

public class Main {
    static int maxA = 0;
    static int maxB = 0;
    static int maxC = 0;
    static boolean[][][] visit = new boolean[201][201][201];

   static HashSet<Integer> result = new HashSet<>();

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        StringTokenizer st = new StringTokenizer(br.readLine()," ");

        maxA = Integer.parseInt(st.nextToken());
        maxB = Integer.parseInt(st.nextToken());
        maxC = Integer.parseInt(st.nextToken());

        bfs();

        ArrayList<Integer> change = new ArrayList<>(result);
        Collections.sort(change);
        for (Integer integer : change) {
            System.out.print(integer+" ");
        } // 결과값을 정렬하기 위해 리스트로 변환 후 정렬
        br.close();
    }

    static void bfs()
    {
        Queue<bottle> q = new LinkedList<>();
        bottle start = new bottle(0,0,maxC);
        visit[0][0][maxC] = true;
        q.add(start);

        while(!q.isEmpty())
        {
            bottle cur = q.poll();
            if(cur.a==0)
            {
                result.add(cur.c);
            }

            // 가능한 경우의 수
            /*  붇는 쪽을 다 붇는 경우
                받는 쪽이 먼저 다 차서 다 못 붇는 경우
            * */
            if(cur.a!=0)
            {
               // a -> b
               int na = cur.a+cur.b;
               int ra = cur.a - (maxB - cur.b);
               if(na<=maxB&&!visit[0][na][cur.c]) // 전부 따를 수 있는 경우
               {
                   visit[0][na][cur.c] = true;
                   q.add(new bottle(0,na,cur.c));
               }

               else if(na>maxB&&!visit[ra][maxB][cur.c]) // 물통이 가득차 일부만 부어야 하는 경우
               {
                   visit[ra][maxB][cur.c] = true;
                   q.add(new bottle(ra,maxB, cur.c));
               }
               // a -> c

                na = cur.a+cur.c;
                ra = cur.a - (maxC - cur.c);
                if(na<=maxC&&!visit[0][cur.b][na])
                {
                    visit[0][cur.b][na] = true;
                    q.add(new bottle(0,cur.b,na));
                }

                else if(na>maxC&&!visit[ra][cur.b][maxC])
                {
                    visit[ra][cur.b][maxC] = true;
                    q.add(new bottle(ra,cur.b, maxC));
                }
            }

            if(cur.b!=0)
            {
                // b -> a
                int nb = cur.a+cur.b;
                int rb = cur.b - (maxA - cur.a);
                if(nb<=maxA&&!visit[nb][0][cur.c])
                {
                    visit[nb][0][cur.c] = true;
                    q.add(new bottle(nb,0,cur.c));
                }

                else if(nb>maxA&&!visit[maxA][rb][cur.c])
                {
                    visit[maxA][rb][cur.c] = true;
                    q.add(new bottle(maxA,rb, cur.c));
                }
                // b -> c

                nb = cur.b+cur.c;
                rb = cur.b - (maxC - cur.c);
                if(nb<=maxC&&!visit[cur.a][0][nb])
                {
                    visit[cur.a][0][nb] = true;
                    q.add(new bottle(cur.a,0,nb));
                }

                else if(nb>maxC&&!visit[cur.a][rb][maxC])
                {
                    visit[cur.a][rb][maxC] = true;
                    q.add(new bottle(cur.a,rb, maxC));
                }
            }

            if(cur.c!=0)
            {
                // c -> a
                int nc = cur.a+cur.c;
                int rc = cur.c - (maxA - cur.a);
                if(nc<=maxA&&!visit[nc][cur.b][0])
                {
                    visit[nc][cur.b][0] = true;
                    q.add(new bottle(nc,cur.b,0));
                }

                else if(nc>maxA&&!visit[maxA][cur.b][rc])
                {
                    visit[maxA][cur.b][rc] = true;
                    q.add(new bottle(maxA,cur.b, rc));
                }

                // c -> b
                nc = cur.c+cur.b;
                rc = cur.c - (maxB - cur.b);

                if(nc<=maxB&&!visit[cur.a][nc][0])
                {
                    visit[cur.a][nc][0] = true;
                    q.add(new bottle(cur.a,nc,0));
                }

                else if(nc>maxB&&!visit[cur.a][maxB][rc])
                {
                    visit[cur.a][maxB][rc] = true;
                    q.add(new bottle(cur.a,maxB, rc));
                }
            }
        }
    }
    // 물을 부울때는 한쪽으로만 붇는다 어느 한 쪽이 다 바닥 낼때까지
}
class bottle
{
    int a;
    int b;
    int c;

    bottle(int a,int b,int c)
    {
        this.a = a;
        this.b = b;
        this.c = c;
    }

}