题意:输入A,B罐容量,求配出C罐方法。A,B罐起始状态都是空的,FILL(i) 表示装满 i 罐,Drop(i)倒掉 i 罐水,Pour(i,j)倒 i 罐水到 j 罐
做这题最大的收获是 数组模仿队列 比 STL的queue好处之一:因为是按照入列顺序当下标,所以用下标保存状态特好。
C++ 的string头文件是<string>,都小写
用A,B罐水作标记,因为如果再次到达这标记状态,那么步数肯定更多,所以没错,具体见代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <string.h>
#include <string>
using namespace std;
string str[] = {"-1","FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
int A,B,C;
struct node
{
int a,b;
int way; //动作->下标数字
int pre; //记录上一个状态的下标
}q[10005]; //队列
bool visit[102][102];
int res[1000];//保存答案的动作
void show(int t)
{
int i = 0;
while(q[t].pre != -1)
{
res[i++] = q[t].way; //保存动作
t = q[t].pre;
}
cout<<i<<endl;
while(i--)
cout<<str[res[i]]<<endl;
}
void bfs(struct node s)
{
node tmp,cur;
int head = 0,tail = 0;
q[tail++] = s;
while( head < tail )
{
cur = q[head];
if(cur.a == C || cur.b == C)
{
show(head); //传递终点状态的下标
return;
}
else
{
for(int i=1;i<=6;i++)
{// {"-1","FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
switch(i)
{
case 1:tmp.a = A, tmp.b = cur.b;break;
case 2:tmp.a = cur.a, tmp.b = B;break;
case 3:tmp.a = 0, tmp.b = cur.b;break;
case 4:tmp.a = cur.a, tmp.b = 0;break;
case 5:
if(cur.b+cur.a >= B)
{
tmp.a = cur.a - (B - cur.b);
tmp.b = B;
}else
{
tmp.a = 0, tmp.b = cur.a+cur.b;
}break;
case 6:
if(cur.b+cur.a >= A)
{
tmp.b = cur.b - (A - cur.a);
tmp.a = A;
}else
{
tmp.a = cur.a + cur.b, tmp.b = 0;
}break;
}
if(!visit[tmp.a][tmp.b])
{
visit[tmp.a][tmp.b] = true;
q[tail].a = tmp.a;
q[tail].b = tmp.b;
q[tail].pre = head;//这里决定了不能先head++,不然用head-1也行
q[tail].way = i;
tail++; //两种方法入列..也可把tmp整个加入
}
}
}
head++;
}
printf("impossible\n");
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
node s;
while(scanf("%d%d%d",&A,&B,&C)!=EOF)
{
memset(visit,false,sizeof(visit));
s.a = s.b = 0;
s.way = 0;
s.pre = -1;
visit[0][0] = true;
bfs(s);
}
return 0;
}