POJ 3414 Pots(bfs+路径记录)




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;  
}   




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值