题目链接:http://poj.org/problem?id=3414
题意:
有两个杯子 a 和 b,第一个杯子 a 的最大容量为 A,第二个杯子 b 的最大容量为B,对于这两个杯子有以下三种操作:
FILL(i):把杯子 i 盛满水.
DROP(i):把杯子 i 中的水全部倒掉.
POUR(i, j):把杯子 i 中的水往杯子 j 中倒,直至杯子 j 中的水为满或者杯子 i 中的水为空.
给你这两个杯子的最大容量 A 和 B,问是否能利用以上三种操作使得某时其中一个杯子的水量恰好为 C,如果可以,输出最少的操作次数,以及操作顺序.如果无论如何操作,都不可能使得其中一个杯子的水量为C,那么输出"impossible".
思路:
可以认为两个杯子的初始状态为(0, 0),经过一系列操作要使得其状态变为(*, C)或者(C, *),其中所有的操作一共有六种:
"FILL(1)":给第一个杯子倒满水;
"FILL(2)":给第二个杯子到满水;
"DROP(1)":把第一个杯子的水倒空;
"DROP(2)":把第二个杯子的水倒空;
"POUR(1, 2)":把第一个杯子里的水往第二个杯子里倒;
"POUR(2, 1)":把第二个杯子里的水往第一个杯子里倒.
所以可以采用暴力求解,对于每种状态都有这六种操作,按照这个思路构造出解答树,对这棵树进行BFS,找到到达终止状态的最少操作数,问题就可以解决.
代码:
1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <stack> 7 #include <queue> 8 #include <vector> 9 #include <algorithm> 10 #include <string> 11 12 typedef long long LL; 13 typedef unsigned long long ULL; 14 using namespace std; 15 const int MAXN = 100; 16 int MaxA, MaxB, C;//Pots A的最大容量;Pots B的最大容量;目标容量 C; 17 const string OPERA[] = {"-1", "FILL(1)", "FILL(2)", "DROP(1)", "DROP(2)", "POUR(1,2)", "POUR(2,1)"};//分别代表六种可能的操作 18 int visit[MAXN + 7][MAXN + 7];//visit[i][j] = 1表示Pots A的水量为 i, Pots B的水量为 j这一状态已经出现过. 19 20 struct Status { 21 int NowA;//此时A中的水量 22 int NowB;//此时B中的水量 23 int step;//到达此状态的操作次数 24 string order;//到达此状态的所有操作 25 }; 26 27 Status BFS() { 28 memset(visit, 0, sizeof(visit)); 29 Status fist;//初始状态 30 fist.NowA = fist.NowB = fist.step = 0; 31 fist.order = ""; 32 queue<Status> Qu; 33 Qu.push(fist);//从初始状态开始BFS 34 visit[0][0] = 1; 35 while(!Qu.empty()) { 36 Status temp = Qu.front(); 37 Qu.pop(); 38 if(temp.NowA == C || temp.NowB == C) return temp;//找到目标状态 39 40 Status nex; 41 42 if(temp.NowA != MaxA) {//A中水不为满,可执行操作1 --> FILL(1) 43 nex.NowA = MaxA, nex.NowB = temp.NowB, nex.step = temp.step + 1;//执行操作1之后,状态发生变化,记录即可 44 if(nex.step == 1) nex.order = temp.order + OPERA[1];//第一个操作前没有回车...... 45 else nex.order = temp.order + " " + OPERA[1]; 46 if(!visit[nex.NowA][nex.NowB]) {//这个状态没有发生过 47 Qu.push(nex); 48 visit[nex.NowA][nex.NowB] = 1; 49 } 50 } 51 52 if(temp.NowB != MaxB) {//B中水不为满,可执行操作2 --> FILL(2) 53 nex.NowA = temp.NowA, nex.NowB = MaxB, nex.step = temp.step + 1; 54 if(nex.step == 1) nex.order = temp.order + OPERA[2]; 55 else nex.order = temp.order + " " + OPERA[2]; 56 if(!visit[nex.NowA][nex.NowB]) { 57 Qu.push(nex); 58 visit[nex.NowA][nex.NowB] = 1; 59 } 60 } 61 62 if(temp.NowA != 0) {//A中水不为空,可执行操作3 --> DROP(1) 63 nex.NowA = 0, nex.NowB = temp.NowB, nex.step = temp.step + 1; 64 if(nex.step == 1) nex.order = temp.order + OPERA[3]; 65 else nex.order = temp.order + " " + OPERA[3]; 66 if(!visit[nex.NowA][nex.NowB]) { 67 Qu.push(nex); 68 visit[nex.NowA][nex.NowB] = 1; 69 } 70 } 71 72 if(temp.NowB != 0) {//B中水不为空,可执行操作4 --> DROP(2) 73 nex.NowA = temp.NowA, nex.NowB = 0, nex.step = temp.step + 1; 74 if(nex.step == 1) nex.order = temp.order + OPERA[4]; 75 else nex.order = temp.order + " " + OPERA[4]; 76 if(!visit[nex.NowA][nex.NowB]) { 77 Qu.push(nex); 78 visit[nex.NowA][nex.NowB] = 1; 79 } 80 } 81 82 if(temp.NowA != 0 && temp.NowB != MaxB) {//A中水不为空,且B中水不为满,可执行操作5 --> POUR(1,2) 83 nex.NowA = max(0, temp.NowA - (MaxB - temp.NowB)), nex.NowB = min(MaxB, temp.NowA + temp.NowB); 84 nex.step = temp.step + 1; 85 if(nex.step == 1) nex.order = temp.order + OPERA[5]; 86 else nex.order = temp.order + " " + OPERA[5]; 87 if(!visit[nex.NowA][nex.NowB]) { 88 Qu.push(nex); 89 visit[nex.NowA][nex.NowB] = 1; 90 } 91 } 92 93 if(temp.NowB != 0 && temp.NowA != MaxA) {//B中水不为空,且A中水不为满,可执行操作6 --> POUR(2,1) 94 nex.NowA = min(MaxA, temp.NowA + temp.NowB), nex.NowB = max(0, temp.NowB - (MaxA - temp.NowA)); 95 nex.step = temp.step + 1; 96 if(nex.step == 1) nex.order = temp.order + OPERA[6]; 97 else nex.order = temp.order + " " + OPERA[6]; 98 if(!visit[nex.NowA][nex.NowB]) { 99 Qu.push(nex); 100 visit[nex.NowA][nex.NowB] = 1; 101 } 102 } 103 } 104 return fist;//没找到答案 105 } 106 107 int main() { 108 scanf("%d%d%d", &MaxA, &MaxB, &C); 109 Status ans = BFS(); 110 if(ans.NowA == C || ans.NowB == C) cout << ans.step << endl << ans.order << endl; 111 else cout << "impossible" << endl; 112 return 0; 113 }