bfs-倒水

Title:有两个容量为A,B的空杯,以及不限量的水。经过一系列对A和B的操作使任意一杯的水量为C。操作包括:“fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。对B同理,即共有6种操作。

Input:输入包含多组数据。每组数据输入 A, B, C
数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。

Output:你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。

样例
Input:
2 7 5
2 7 4

Output:
fill B
pour B A
success
fill A
pour A B
fill A
pour A B
success

分析:倒水问题其实可以类比迷宫问题。

  • 某一时刻A和B两个杯子的水量等价于迷宫中的某个点坐标;
  • 对A和B进行6种操作等价于对迷宫中的某个点进行上下左右的移动;
  • 标记A和B的下一个状态是否出现过,等价于标记迷宫中某个点是否已经被访问过,在本次代码中,使用了map<point,point> pre,在记录状态和状态之间的联系的同时,可以通过pre.find(point A)==pre.end()是否为真,来判断状态A是否已经被访问。
  • 对于输出一系列的操作,只需要在结构体中增加一个int型成员op,用于记录该状态是由哪一种操作(对6种操作进行编号0-5)形成的,将迷宫问题中的输出点改为输出op对应的字符串即可

需要注意的是

  • 在倒满A杯之前需要判断A杯是否已经满了,已满则不需要进行倒满A的操作;
  • 在倒空A杯之前需要判断A杯是否已经是空;已空则不需要进行倒空A的操作;
  • 对于B杯也同理。这样可以减少那些不必要的分支,例如一直在倒满A,一直在倒空A。

对6种操作进行编号并输出
1.使用一个一维数组a
a[0]为“fill A”;a[1]为“empty A”,依此类推。只要输出a[op]即可输出相应的操作。
2.使用map
map<int,string> mp;mp.insert({0,“fill A”});输出mp.find(op)->second即可输出相应的操作。
3.递归输出思想与迷宫问题中的输出类似。

代码变量解释
结构体point用于记录A和B的当前状态,x,y分别表示A和B当前的水量;

#include<iostream>
#include<queue>
#include<map>
#include<string>
using namespace std;
map<int, string> mp;
struct point
{
 int x;
 int y;
 int op;
 point(int thex, int they, int theop)
 {
  x = thex;
  y = they;
  op = theop;
 }
 point(int thex, int they)
 {
  x = thex;
  y = they;
  op = -1;
 }
 point()
 {
  x = 0;
  y = 0;
  op = -1;
 }
 bool operator<(const point& p) const
 {
  return x != p.x ? x < p.x : y < p.y;
 }
};
map<point, point> pre;
void output(point p)
{
 if ((p.x == 0 && p.y == 0))
  return;
 output(pre[p]); // 递归
 cout << mp.find(p.op)->second << endl;
}
void bfs(int A,int B,int C)
{
 point begin(0, 0);
 queue<point> que;
 //起点入队列
 que.push(begin);
 while (!que.empty())
 {
  point now = que.front();
  que.pop();
  //到达终点
  if (now.x == C || now.y == C)
  {
   output(now);
   cout << "success" << endl;
   return;
  }
  //选择下一步,一共6种选择
  for (int i = 0; i < 6; i++)
  {
   if (i == 0)
   {
    //A没满,倒满A
    if (now.x != A)
    {
     if(pre.find(point(A, now.y, i))==pre.end())//判断有没有走到这一个状态
      {   
          pre[point(A, now.y, i)] = now;
          que.push(point(A, now.y, i));
      } 
    }
   }
   //A没空,倒空A
   else if (i == 1)
   {
    if (now.x != 0)
    {
     if (pre.find(point(0, now.y, i)) == pre.end())
     {
      que.push(point(0, now.y, i));
      pre[point(0, now.y, i)] = now;
     }  
    }
   }
   //A倒B,B满或A空
   else if (i == 2)
   {
    //A不空才能倒
    if (now.x != 0)
    {
     //B到满的距离和A到空的距离比较
     if (B - now.y <= now.x)//B会倒满
     {
      if (pre.find(point(now.x + now.y - B, B, i)) == pre.end())
      {
       que.push(point(now.x + now.y - B, B, i));
       pre[point(now.x + now.y - B, B, i)] = now;
      }
     }
     else//A会倒空
     { 
      if (pre.find(point(0, now.x + now.y, i)) == pre.end())
      {
       que.push(point(0, now.x + now.y, i));
       pre[point(0, now.x + now.y, i)] = now;
      }
     }
    }
   }
   //B没满,倒满B
   else if (i == 3)
   {
    if (now.y != B)
    {
     if (pre.find(point(now.x, B, i)) == pre.end())
     {
      que.push(point(now.x, B, i));
      pre[point(now.x, B, i)] = now;
     }
    }
   }
   //B没空,倒空B
   else if (i == 4)
   {
    if (now.y != 0)
    {
     if (pre.find(point(now.x, 0, i)) == pre.end())
      {
       que.push(point(now.x, 0, i));
       pre[point(now.x, 0, i)] = now;
     }   
    }
   }
   //B倒A,A满或B空
   else
   {
    //B不空才能倒
    if (now.y != 0)
    {
     //A到满的距离和B到空的距离比较
     if (A - now.x <= now.y)//A会倒满
     {
      if (pre.find(point(A, now.x + now.y - A, i)) == pre.end())
       {
        que.push(point(A, now.x + now.y - A, i));
        pre[point(A, now.x + now.y - A, i)] = now;
       }
     }
     else//B会倒空
     {
      if (pre.find(point(now.x + now.y, 0, i)) == pre.end())
      {
       que.push(point(now.x + now.y, 0, i));
       pre[point(now.x + now.y, 0, i)] = now;
      } 
     }
    }
   }
  }
 }
}
int main()
{
 mp.insert({0,"fill A"}); 
 mp.insert({1,"empty A"}); 
 mp.insert({2,"pour A B"}); 
 mp.insert({3,"fill B" });
 mp.insert({4,"empty B" });
 mp.insert({5,"pour B A" });
 int A=0, B=0, C=0;
 while (cin >> A >> B >> C)
 {
  pre.clear();
  bfs(A, B, C);
 }
 return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值