Backwater problem (dp+bfs)

Keywords: Java

1 Problem Description

There are three cups, A, B and C, without calibration. The capacity is A, B and C respectively. How to measure the water with the capacity of K when only using these three cups?

Requirements: Water can be used indefinitely. Water in each cup can be poured out, refilled or poured into other cups.

2 state analysis

In terms of the amount of water in each cup, that is, the state node is represented by a triple (a, b, c), and there are (A+1)*(B+1)*(C+1) states. If the T2 state can be reached by one step pouring operation from T1 state, there is an edge between T1 and T2, which is recorded as T1 - > T2, thus a directed graph can be established.

For each state, there are at most 12 state transition rules as follows:

  • If a > 0 => a=0; (pour out A cup of water)
  • If b > 0 => b=0; (pour out B cup of water)
  • If C > 0 => c=0; (pour out C cup of water)
  •  
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Stack;

class Status{
	int a;
	int b;
	int c;
	Status(int a,int b,int c){
		this.a=a;
		this.b=b;
		this.c=c;
	}
}
public class Main3 {
	static int A,B,C,K;
	static int[][][] dp;
	static int ans;
	static final int MAX=10000000;
	static Status[][][] plan;
	static LinkedList<Status> list=new LinkedList<Status>();
	
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		A=sc.nextInt();
		B=sc.nextInt();
		C=sc.nextInt();
		K=sc.nextInt();
		dp=new int[A+1][B+1][C+1];
		plan=new Status[A+1][B+1][C+1];
		for(int i=0;i<=A;i++) {
			for(int j=0;j<=B;j++) {
				for(int k=0;k<=C;k++) {
					dp[i][j][k]=MAX;
					plan[i][j][k]=new Status(0,0,0);
				}
			}
		}
		bfs();
		Status status=choose();
		print(status);
	}
	
	static void bfs() {
		dp[0][0][0]=0;
		plan[0][0][0]=null;
		list.add(new Status(0,0,0));
		while(!list.isEmpty()) {
			Status sta=list.remove();
			int a=sta.a;
			int b=sta.b;
			int c=sta.c;
			for(int i=0;i<12;i++) {
				Status s=change(a,b,c,i);
				if(s!=null) {
					list.add(s);
				}
			}
		}
	}
	
	static Status choose() {
		int a=0,b=0,c=0;
		ans=MAX;
		if(K<=C) {
			for(int i=0;i<=A;i++) {
				for(int j=0;j<=B;j++) {
					if(dp[i][j][K]<ans) {
						ans=dp[i][j][K];
						a=i;
						b=j;
						c=K;
					}
				}
			}
		}
		if(K<=B) {
			for(int i=0;i<=A;i++) {
				for(int k=0;k<=C;k++) {
					if(dp[i][K][k]<ans) {
						ans=dp[i][K][k];
						a=i;
						b=K;
						c=k;
					}
				}
			}
		}
		if(K<=A) {
			for(int j=0;j<=B;j++) {
				for(int k=0;k<=C;k++) {
					if(dp[K][j][k]<ans) {
						ans=dp[K][j][k];
						a=K;
						b=j;
						c=k;
					}
				}
			}
		}
		return new Status(a,b,c);
	}
	
	static void print(Status status) {
		Stack<Status> stack=new Stack<Status>();
		while(status!=null) {
			stack.add(status);
			int a=status.a;
			int b=status.b;
			int c=status.c;
			status=plan[a][b][c];
		}
		while(!stack.isEmpty()) {
			status=stack.pop();
			int a=status.a;
			int b=status.b;
			int c=status.c;
			if(stack.size()>0)
				System.out.print("("+a+","+b+","+c+")->");
			else
				System.out.print("("+a+","+b+","+c+")");
		}
		System.out.println("\n"+ans);
	}
	
	static Status change(int i,int j,int k,int s) {
		Status sta=new Status(i,j,k);
		switch(s) {
			case 0: //Empty A cup of water
				if(i>0) {
					if(dp[0][j][k]>dp[i][j][k]+1) {
						dp[0][j][k]=dp[i][j][k]+1;
						plan[0][j][k]=sta;
						return new Status(0,j,k);
					}
				}
				return null;
			case 1: //Empty B cup of water
				if(j>0) {
					if(dp[i][0][k]>dp[i][j][k]+1) {
						dp[i][0][k]=dp[i][j][k]+1;
						plan[i][0][k]=sta;
						return new Status(i,0,k);
					}
				}
				return null;
			case 2:  //Empty C cup of water
				if(k>0) {
					if(dp[i][j][0]>dp[i][j][k]+1) {
						dp[i][j][0]=dp[i][j][k]+1;
						plan[i][j][0]=sta;
						return new Status(i,j,0);
					}
				}
				return null;
			case 3:  //Fill up A glass of water
				if(i<A) {
					if(dp[A][j][k]>dp[i][j][k]+1) {
						dp[A][j][k]=dp[i][j][k]+1;
						plan[A][j][k]=sta;
						return new Status(A,j,k);
					}
				}
				return null;
			case 4:  //Fill up B cups of water
				if(j<B) {
					if(dp[i][B][k]>dp[i][j][k]+1) {
						dp[i][B][k]=dp[i][j][k]+1;
						plan[i][B][k]=sta;
						return new Status(i,B,k);
					}
				}
				return null;
			case 5: //Fill up a C cup of water
				if(k<C) {
					if(dp[i][j][C]>dp[i][j][k]+1) {
						dp[i][j][C]=dp[i][j][k]+1;
						plan[i][j][C]=sta;
						return new Status(i,j,C);
					}
				}
				return null;
			case 6: //B->A
				if(j>0&&i<A) {
					if(i+j<=A) {
						if(dp[i+j][0][k]>dp[i][j][k]+1) {
							dp[i+j][0][k]=dp[i][j][k]+1;
							plan[i+j][0][k]=sta;
							return new Status(i+j,0,k);
						}
					}else {
						if(dp[A][i+j-A][k]>dp[i][j][k]+1) {
							dp[A][i+j-A][k]=dp[i][j][k]+1;
							plan[A][i+j-A][k]=sta;
							return new Status(A,i+j-A,k);
						}
					}
				}
				return null;
			case 7: //C->A
				if(k>0&&i<A) {
					if(i+k<=A) {
						if(dp[i+k][j][0]>dp[i][j][k]+1) {
							dp[i+k][j][0]=dp[i][j][k]+1;
							plan[i+k][j][0]=sta;
							return new Status(i+k,j,0);
						}
					}else {
						if(dp[A][j][i+k-A]>dp[i][j][k]+1) {
							dp[A][j][i+k-A]=dp[i][j][k]+1;
							plan[A][j][i+k-A]=sta;
							return new Status(A,j,i+k-A);
						}
					}
				}
				return null;
			case 8: //A->B
				if(i>0&&j<B) {
					if(i+j<=B) {
						if(dp[0][i+j][k]>dp[i][j][k]+1) {
							dp[0][i+j][k]=dp[i][j][k]+1;
							plan[0][i+j][k]=sta;
							return new Status(0,i+j,k);
						}
					}else {
						if(dp[i+j-B][B][k]>dp[i][j][k]+1) {
							dp[i+j-B][B][k]=dp[i][j][k]+1;
							plan[i+j-B][B][k]=sta;
							return new Status(i+j-B,B,k);
						}
					}
				}
				return null;
			case 9: //C-B
				if(k>0&&j<B) {
					if(j+k<=B) {
						if(dp[i][j+k][0]>dp[i][j][k]+1) {
							dp[i][j+k][0]=dp[i][j][k]+1;
							plan[i][j+k][0]=sta;
							return new Status(i,j+k,0);
						}
					}else {
						if(dp[i][B][j+k-B]>dp[i][j][k]+1) {
							dp[i][B][j+k-B]=dp[i][j][k]+1;
							plan[i][B][j+k-B]=sta;
							return new Status(i,B,j+k-B);
						}
					}
				}
				return null;
			case 10: //A->C
				if(i>0&&k<C) {
					if(i+k<=C) {
						if(dp[0][j][i+k]>dp[i][j][k]+1) {
							dp[0][j][i+k]=dp[i][j][k]+1;
							plan[0][j][i+k]=sta;
							return new Status(0,j,i+k);
						}
					}else {
						if(dp[i+k-C][j][C]>dp[i][j][k]+1) {
							dp[i+k-C][j][C]=dp[i][j][k]+1;
							plan[i+k-C][j][C]=sta;
							return new Status(i+k-C,j,C);
						}
					}
				}
				return null;
			case 11: //B->C
				if(j>0&&k<C) {
					if(j+k<=C) {
						if(dp[i][0][j+k]>dp[i][j][k]+1) {
							dp[i][0][j+k]=dp[i][j][k]+1;
							plan[i][0][j+k]=sta;
							return new Status(i,0,j+k);
						}
					}else {
						if(dp[i][j+k-C][C]>dp[i][j][k]+1) {
							dp[i][j+k-C][C]=dp[i][j][k]+1;
							plan[i][j+k-C][C]=sta;
							return new Status(i,j+k-C,C);
						}
					}
				}
				return null;
		}
		return null;
	}
}

 

Posted by bhogg on Mon, 07 Oct 2019 18:48:49 -0700