PS/BOJ2022. 5. 1. 16:22

 

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

 

 

BFS

1. 비효율적이긴 하지만 ArraysCopyOf 함수를 활용해보고 싶었다.

2. 이전 퍼즐문제에서 사용했던, HashMap 및 String을 조합하여 중복을 체크하였다.

String.format을 사용해 a,b,c 현재 물의 양을 Key값으로 함.

 

3. 숏코드에서 확인한 바와 같이 2차원 배열을 활용하여 중복을 체크하는 것이 성능상 더 나은 선택이 되겠다.

(전체 물의 양이 정해져 있으므로 A,B 값을 체크하면 C의 값은 확인할 필요가 없다.)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {

	static int N;
	static boolean DBG = false;
	static HashMap<String, Integer> dup;
	static HashSet<Integer> answer;
	static int[] arr;
	static int[] init;

	static int A = 0;
	static int B = 1;
	static int C = 2;

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		arr = new int[3];
		init = new int[3];
		dup = new HashMap<>();
		answer= new HashSet<>();
		// 0 size , 1 water
		for (int t = 0; t < 3; t++) {
			arr[t] = Integer.parseInt(st.nextToken());
		}

		// init only 3rd has water
		init[C] = arr[C];
		bfs();
		
		ArrayList<Integer> ar = new ArrayList<>(answer);
		Collections.sort(ar);
		for ( int v : ar)
			System.out.print(v + " ");

	}

	private static int bfs() {
		Queue<int[]> Q = new LinkedList<>();

		// 초기 A의 물은 없으므로 현재 물의 양을 저장
		String initKey = String.format("%d%d%d", init[A], init[B], init[C]);
		dup.put(initKey, init[C]);
		answer.add(init[C]);
		
		Q.offer(Arrays.copyOf(init, init.length));

		while (!Q.isEmpty()) {
			int size = Q.size();
			int level = 0;
			for (int q = 0; q < size; ++q) {
				int[] water = Q.poll();
				deliverWater(A, B, Arrays.copyOf(water, water.length), Q);
				deliverWater(A, C, Arrays.copyOf(water, water.length), Q);
				deliverWater(B, A, Arrays.copyOf(water, water.length), Q);
				deliverWater(B, C, Arrays.copyOf(water, water.length), Q);
				deliverWater(C, A, Arrays.copyOf(water, water.length), Q);
				deliverWater(C, B, Arrays.copyOf(water, water.length), Q);
				
			}
			level++;
		}
		return -1;
	}

	static void deliverWater(int src, int dst, int [] water , Queue<int[]> Q){
		if (water[src] != 0) {
			//src to dst
			int empty = (arr[dst] - water[dst]);//빈공간
			int capacity = (water[src] > empty)? empty: water[src]; //A물을 얼마나 빈공간에 넣을 수 있는가?
			
			water[src] -= capacity;
			water[dst] += capacity;

			String tmp = String.format("%d%d%d", water[A], water[B], water[C]);
			if( DBG )
			System.out.println(tmp);
			if (!dup.containsKey(tmp)) {
				dup.put(tmp, water[C]);
				
				//A가 0일 경우만 C의 물의 양이 정답에 추가됨.
				if (water[A] == 0)
					answer.add(water[C]);						
				Q.offer(Arrays.copyOf(water, water.length));
			}
		}
	}
	
}









//숏코드 참조하여 개선한 버전
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Main {

	static boolean DBG = false;
	static boolean[][] dup;
	static TreeSet<Integer> answer;
	static int[] arr;
	static int[] init;

	static int A = 0;
	static int B = 1;
	static int C = 2;

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		arr = new int[3];
		init = new int[3];
		dup = new boolean[201][201];
		answer = new TreeSet<>();
		// 0 size , 1 water
		for (int t = 0; t < 3; t++) {
			arr[t] = Integer.parseInt(st.nextToken());
		}
		// init only 3rd has water
		init[C] = arr[C];
		bfs();

		ArrayList<Integer> ar = new ArrayList<>(answer);
		for (int v : ar)
			System.out.print(v + " ");

	}

	private static int bfs() {
		Queue<int[]> Q = new LinkedList<>();

		// 초기 A의 물은 없으므로 현재 물의 양을 저장
		dup[init[A]][init[B]] = true;
		answer.add(init[C]);

		Q.offer(Arrays.copyOf(init, init.length));

		while (!Q.isEmpty()) {
			int size = Q.size();
			for (int q = 0; q < size; ++q) {
				int[] water = Q.poll();
				// A가 0일 경우만 C의 물의 양이 정답에 추가됨.
				if (water[A] == 0)
					answer.add(water[C]);

				deliverWater(A, B, Arrays.copyOf(water, water.length), Q);
				deliverWater(A, C, Arrays.copyOf(water, water.length), Q);
				deliverWater(B, A, Arrays.copyOf(water, water.length), Q);
				deliverWater(B, C, Arrays.copyOf(water, water.length), Q);
				deliverWater(C, A, Arrays.copyOf(water, water.length), Q);
				deliverWater(C, B, Arrays.copyOf(water, water.length), Q);
			}
		}
		return -1;
	}

	static void deliverWater(int src, int dst, int[] water, Queue<int[]> Q) {

		int empty = (arr[dst] - water[dst]);// 빈공간
		int capacity = (water[src] > empty) ? empty : water[src];

		water[src] -= capacity;
		water[dst] += capacity;

		if (DBG)
			System.out.printf("%d%d%d\n", water[A], water[B], water[C]);

		if (!dup[water[A]][water[B]]) {
			dup[water[A]][water[B]] = true;
			Q.offer(Arrays.copyOf(water, water.length));
		}
	}

}

 

 

 

DFS 

 

DFS 참조

1.https://www.acmicpc.net/source/11839520

2.https://loosie.tistory.com/513

 

생각하지 못한점.

1. TreeSet을 사용하면 정렬을 해줄 필요가 없다.

2. 중복체크는 a,b의 값을 좌표로한 2by2 배열로 가능하다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Main {

	static boolean DBG = false;
	static boolean[][] dup;
	static TreeSet<Integer> answer;

	// size of bucket
	static int A;
	static int B;
	static int C;

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		dup = new boolean[201][201];
		answer = new TreeSet<>();

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

		dfs(0, 0, C);

		ArrayList<Integer> ar = new ArrayList<>(answer);		
		for (int v : ar)
			System.out.print(v + " ");

	}

	private static void dfs(int a, int b, int c) {

		if (dup[a][b])
			return;

		if (a == 0) {
			answer.add(c);
		}

		dup[a][b] = true;

		// A->B
		if (a + b > B)
			dfs(a + b - B, B, c);
		else
			dfs(0, a + b, c);

		// A->C
		if (a + c > C)
			dfs(a + c - C, b, C);
		else
			dfs(0, b, a + c);

		// B->A
		if (a + b > A)
			dfs(A, a + b - A, c);
		else
			dfs(a + b, 0, c);
		// B->C
		if (b + c > C)
			dfs(a, b + c - C, C);
		else
			dfs(a, 0, b + c);
		// C->A
		if (a + c > A)
			dfs(A, b, a + c - A);
		else
			dfs(a + c, b, 0);
		// C->B
		if (b + c > B)
			dfs(a, B, b + c - B);
		else
			dfs(a, b + c, 0);

	}

}

 

 

'PS > BOJ' 카테고리의 다른 글

3108  (0) 2022.05.02
2186(중요)  (0) 2022.05.01
1525  (0) 2022.05.01
9019  (0) 2022.04.30
1963  (0) 2022.04.30
Posted by easy16