Description
You are given two pots, having the volume of A and B liters respectively. The following operations can be performed:
FILL(i) fill the pot i (1 ≤ i ≤ 2) from the tap;
DROP(i) empty the pot i to the drain;
POUR(i,j) pour from pot i to pot j; after this operation either the pot j is full (and there may be some water left in the pot i), or the pot i is empty (and all its contents have been moved to the pot j).
Write a program to find the shortest possible sequence of these operations that will yield exactly C liters of water in one of the pots.
Input
On the first and only line are the numbers A, B, and C. These are all integers in the range from 1 to 100 and C≤max(A,B).
Output
The first line of the output must contain the length of the sequence of operations K. The following K lines must each describe one operation. If there are several sequences of minimal length, output any one of them. If the desired result can’t be achieved, the first and only line of the file must contain the word ‘impossible’.
Sample Input
3 5 4
Sample Output
6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)
解题思路:利用BFS,每次入队都有六种情况:将A充满,将B充满,倒空A,倒空B,将A倒向B,将B倒向A(注意防溢出,体积有限制);记住每次操作的前驱;利用递归回溯输出步骤!
代码如下:
#include<stdio.h>
#include<string.h>
int judge[101][101]; //判断是否出现过,剪枝
char str[6][100] = {"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"}; //便于输出
struct Q
{
int a,b;
int step;
int num; //记住每次的操作类型
int pri; //记住前驱
}queue[105*105]; //队列数组
void BFS(int a,int b,int c); //广搜
void print(int x); //递归回溯
int min(int a,int b); //取小
int main()
{
int a,b,c;
while(~scanf("%d%d%d",&a,&b,&c))
{
memset(judge,0,sizeof(judge)); //注意初始化,避免对二次的输入产生影响
BFS(a,b,c);
}
return 0;
}
void BFS(int a,int b,int c)
{
struct Q temp;
int wat;
int head = 0 , rear = 0; //head表示队列的头,rear表示队列的尾
queue[rear].a = 0; //初始化
queue[rear].b = 0;
queue[rear].pri = -1;
queue[rear++].step = 0;
judge[0][0] = 1;
while(head < rear) //队列不为空
{
temp = queue[head];
if(temp.a == c || temp.b == c) //已找到,输出次数和方案
{
printf("%d\n",temp.step); //次数
print(head); //方案
return ;
}
if(!judge[a][temp.b]) //第一种,充满A,下面同理
{
queue[rear].num = 0; //类型
queue[rear].a = a;
queue[rear].b = temp.b;
queue[rear].pri = head; //标记前驱
queue[rear++].step = temp.step+1;
judge[a][temp.b] = 1; //标记,剪枝,避免重复出现,导致队列无限长
}
if(!judge[temp.a][b]) //第二种,充满B
{
queue[rear].num = 1;
queue[rear].a = temp.a;
queue[rear].b = b;
queue[rear].pri = head;
queue[rear++].step = temp.step+1;
judge[temp.a][b] = 1;
}
if(!judge[0][temp.b]) //第三种,倒空A
{
queue[rear].num = 2;
queue[rear].a = 0;
queue[rear].b = temp.b;
queue[rear].pri = head;
queue[rear++].step = temp.step+1;
judge[0][temp.b] = 1;
}
if(!judge[temp.a][0]) //第四种,倒空B
{
queue[rear].num = 3;
queue[rear].a = temp.a;
queue[rear].b = 0;
queue[rear].pri = head;
queue[rear++].step = temp.step+1;
judge[temp.a][0] = 1;
}
wat = min(temp.a,b-temp.b); //避免溢出
if(!judge[temp.a-wat][temp.b+wat]) //第五种,把A倒向B
{
queue[rear].num = 4;
queue[rear].a = temp.a-wat;
queue[rear].b = temp.b+wat;
queue[rear].pri = head;
queue[rear++].step = temp.step+1;
judge[temp.a-wat][temp.b+wat] = 1;
}
wat = min(a-temp.a,temp.b);
if(!judge[temp.a+wat][temp.b-wat]) //第六种,把B倒向A
{
queue[rear].num = 5;
queue[rear].a = temp.a+wat;
queue[rear].b = temp.b-wat;
queue[rear].pri = head;
queue[rear++].step = temp.step+1;
judge[temp.a+wat][temp.b-wat] = 1;
}
head++;
}
printf("impossible\n"); //当队列为空时,还没找到,则输出不可能
}
void print(int x)
{
if(queue[x].pri != -1)
{
print(queue[x].pri); //利用递归进行回溯
printf("%s\n",str[queue[x].num]);
}
}
int min(int a,int b)
{
return a<b?a:b;
}