前一段时间看了题面,第一感觉就是自己肯定不会做,今天试了一下,尽然写出来了。
祝贺自己的进步吧~~^_^
POJ 3414 Pot: http://poj.org/problem?id=3414
题目大意: 给两个尿壶 大小为 A升和B升
三种操作 : 把A或者B尿壶 倒空
把A或者B尿壶灌满
把A尿壶的水灌到B壶里面,如果B灌满了,就停止,A的壶剩着等待下一个操作,反过来是一样的。
问: 怎么个倒法,能最少操作次数,灌出个 C升的水。
要求输出最小次数,以及 如何操作!
求最少次数还好,DFS不方便,BFS最快捷。
但是怎么输出操作步骤呢?
想了一段时间,我的解决方法是,每时刻,两壶里的水量 i,j ,都存储一个 上一状态的的倒法。 也就是存储,上一状态的i和j,以及倒法(用字母表示)
用book来标记哪些水量倒出来过了,一旦C升的水倒出来了就进行输出操作。
输出操作我是用递归倒着来解决。最终升的状态存储了上一次倒的状态以及倒法,而上一次的倒的状态,又存储了上上次的状态以及倒法。直到初始状态以后,就可以逐层输出啦。
可能说的有点混。总结一下,我是
用BFS进行搜索最少次数,并同时记录每个状态的最少次数时,对应的上一状态(这里的“”最少“”依靠BFS的特性,不要纠结)。在BFS到了目标水量后,就用递归输出。
给出以下代码,不清楚的地方可以问,会更新。
BFS:
#include"cstdio"
#include"cstring"
#include"queue"
#include"algorithm"
using namespace std;
#define inf 109
#define loop(x,y,z) for(x=y;x<z;x++)
int a,b,c,sum;
int book[inf];
struct point
{int i,j;
point()
{
}
point(int x,int y)
{
i=x;j=y;
}
};
struct node
{
int li,lj;
char verb;
int cup;
int step;
void set(int i,int j,int k,char c)
{
li=i;lj=j;cup=k;verb=c;;
}
}pos[inf][inf];
queue<point>q;
void init()
{
while(!q.empty())q.pop();
memset(pos,-1,sizeof pos);
memset(book,0,sizeof book);
sum=0;
}
void print(int i,int j)
{
char x=pos[i][j].verb;
int y=pos[i][j].cup;
if(x=='F')
{
printf("FILL(%d)\n",y);
}
else if(x=='P')
{
int z=(y==1)?2:1;
printf("POUR(%d,%d)\n",y,z);
}
else if(x=='D')
{
printf("DROP(%d)\n",y);
}
}
void dfs(int i,int j)
{
if(i==0&&j==0)
{printf("%d\n",sum);return;}
sum++;
dfs(pos[i][j].li,pos[i][j].lj);
print(i,j);//printf("now dfs point is %d %d , and its next point is %d %d\n",i,j,pos[i][j].li,pos[i][j].lj);
}
point fill(int i,int j,int tag)
{
if(tag==0)i=a;
else j=b;
return point(i,j);
}
point drop(int i,int j,int tag)
{
if(tag==0)i=0;
else j=0;
return point(i,j);
}
point pour(int i,int j,int tag)
{
if(tag==0)
{
int t=i+j;
if(t>b)
{
j=b;
i=t-b;
}
else
{
j=t;
i=0;
}
}
else
{
int t=i+j;
if(t>a)
{
i=a;
j=t-a;
}
else
{
i=t;
j=0;
}
}
return point(i,j);
}
void bfs()
{
int i,j,x,y;
q.push(point(0,0)); //压入首点
book[0]=1; //标记首点
while(!q.empty())
{
point t=q.front(); //取出队首
q.pop(); //吐掉
for(i=0;i<6;i++)
{
point tag; //tag为变化后点
if(i<2)
{
tag=fill(t.i,t.j,i%2);
x=tag.i;
y=tag.j;
if(pos[x][y].li==-1&&pos[x][y].lj==-1) //如果变化后点未出现过
{
pos[x][y].set(t.i,t.j,i%2+1,'F'); //记录,标记,入队
book[x]=book[y]=1;
q.push(tag);
if(book[c]) //若出现目的水量,输出并结束
{
dfs(tag.i,tag.j);return;
}
}
}
else if(i<4) //下同
{
tag=drop(t.i,t.j,i%2);
x=tag.i;
y=tag.j;
if(pos[x][y].li==-1&&pos[x][y].lj==-1)
{
pos[x][y].set(t.i,t.j,i%2+1,'D');
book[x]=book[y]=1;
q.push(tag);
if(book[c])
{
dfs(tag.i,tag.j);return;
}
}
}
else
{
tag=pour(t.i,t.j,i%2);
x=tag.i;
y=tag.j;
if(pos[x][y].li==-1&&pos[x][y].lj==-1)
{
pos[x][y].set(t.i,t.j,i%2+1,'P');
book[x]=book[y]=1;
q.push(tag);
if(book[c])
{
dfs(tag.i,tag.j);return;
}
}
}
}
}
printf("impossible\n");
}
int main()
{
scanf("%d%d%d",&a,&b,&c);
init();
bfs();
return 0;
}