http://poj.org/problem?id=3414
路径记录的题对于初学者来说的确很难 但是只要你真正明白了是怎么回事 到底该怎么把路径给记录下来 问题就变得简单了
题意: 给定两个杯子和它们的容积 通过他们互相之间倒水 问能不能 凑出 给定的目标水量
可以用bfs来做 搜索找到最终结果并不难 难在路径的记录
路径该怎么记录呢。。。。。 就是每一步都记住上一步是什么 当其中有一步是结果时 就依次找回最初状态 具体到本题中在结构体中 设置两个变量 一个记住本身 一个记住上一状态数组
每个状态(结点) 下都有六种情况
1、将A杯子倒满;
2、将B杯子倒满;
3、将A杯子倒空;
4、将B杯子倒空;
5、将A杯子中的水倒向B杯子;
这里要分情况讨论:
如果两个杯子中水的总量大于B杯子的总量 那么B杯子将会被倒满 A杯子中的水为剩下的;
如果两个杯子中水的总量小于等于B杯子的总量 那么所有的水都倒进B杯子中 A杯子中没有水了;
6、将B杯子中的水倒向A杯子(这里和 5 是一样的);
AC代码:
#include <stdio.h>
#include <queue>
#include <string.h>
using namespace std;
int a,b,c;
int vis[110][110];//用来记录每种状态是否出现过 如果出现过后面就不用重复进行 这个数组一定要有 不然。。。。。。。。。
int flag1;// 用来标记是否可以凑出 目标水量
struct node{
int A;// A杯子
int B;// B杯子
int flag;// 用来记住本身数组的下标 (路径记录用)
int pre;// 用来记住父结点数组的下表 (路径记录用)
int step;// 用来记录这是第几步
int p;// 用来记录这一步的操作是什么 (输出结果用)
}NODE[20000];
void Printf(int i){
if(i!=-1)
Printf(NODE[i].pre);// 将结果递归输出
if (NODE[i].p==1){
printf ("FILL(1)\n");
}
else if(NODE[i].p==2){
printf ("FILL(2)\n");
}
else if(NODE[i].p==3){
printf ("DROP(1)\n");
}
else if(NODE[i].p==4){
printf ("DROP(2)\n");
}
else if (NODE[i].p==5){
printf ("POUR(1,2)\n");
}
else if (NODE[i].p==6){
printf ("POUR(2,1)\n");
}
}
void bfs(){
queue<node> Q;
NODE[0].A=0;
NODE[0].B=0;
NODE[0].flag=0;
NODE[0].pre=-1;
NODE[0].step=0;
NODE[0].p=0;
Q.push(NODE[0]);
vis[0][0]=1;
node temp;
int j=1;
while (!Q.empty()){
temp=Q.front();
Q.pop();
if (temp.A==c||temp.B==c){
printf ("%d\n",temp.step);
Printf(temp.flag);
flag1=1;
break;
}
for (int i=1;i<=6;i++){
NODE[j]=temp;
if (i==1)// 情况 1
{
NODE[j].A=a;
}
else if(i==2)// 情况 2
{
NODE[j].B=b;
}
else if(i==3)// 情况 3
{
NODE[j].A=0;
}
else if(i==4)// 情况 4
{
NODE[j].B=0;
}
else if (i==5)// 情况 5
{
if(NODE[j].A+NODE[j].B>b){
NODE[j].A=NODE[j].A+NODE[j].B-b;
NODE[j].B=b;
}
else {
NODE[j].B=NODE[j].A+NODE[j].B;
NODE[j].A=0;
}
}
else if (i==6)// 情况 6
{
if (NODE[j].A+NODE[j].B>a){
NODE[j].B=NODE[j].A+NODE[j].B-a;
NODE[j].A=a;
}
else {
NODE[j].A=NODE[j].A+NODE[j].B;
NODE[j].B=0;
}
}
if(!vis[NODE[j].A][NODE[j].B]){
NODE[j].p=i;// 记住这一步操作
NODE[j].flag=j;// 记住本身数组下标
NODE[j].pre=temp.flag;// 记住父结点数组的下标
NODE[j].step+=1;
Q.push(NODE[j]);
vis[NODE[j].A][NODE[j].B]=1;// 出现过的状态标记为 1
j++;
}
}
}
}
int main (){
scanf ("%d%d%d",&a,&b,&c);
memset(vis,0,sizeof(vis));// 全部初始化为没有被标记过
flag1=0;
bfs();
if(!flag1){
printf ("impossible\n");
}
return 0;
}