2017-03-04 分油问题

Description

设有大小不等的3个无刻度的油桶,分别能盛满 X、Y、Z(都小于等于 100)升油,初始时第一个油桶盛满,另外两个为空。现在,要想在某一瓶中分出 T升油。分油时可把一个桶里的油倒入另外的桶中,或者将桶中的油倒空。设计一种以最少步骤的分油方案。

Input

第一行:X Y Z {设第一个油桶 X 已装满油}
第二行:T {要分出的目标油量}

Output

输出最少步数,若无法分出 T 升油,则输出“NO ANSWER! ” 。

Sample Input

80 50 30
60

Sample Output

3

Source

BFS

Solution

用4个queue<>分别存桶1,2,3状态,和达到这个状态所用的步数;用一个循环不断枚举状态,还需要一个三维数组判重,因为数据范围不大,所以不会超空间,如果当前情况下某个桶内有油,就枚举它往其它两个桶倒和把油倒了不要的情况,如果到达的状态没有出现过,就存入queue。枚举完此状态之后要弹出,弹完了就是状态枚举完了;如果从一开始初始值油量就小于目标值油量,那么当然可以直接输出no answer

Code

/*
  类似与广搜,但是每当搜索过一个状态之后后就会弹出这个状态,直到枚举完所有的状态,如果没能达到目标状态,则输出no answer
 */
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
queue<int>x,y,z,ans;
int a,b,c,n;
bool g[101][101][101];//用于判重 
bool flag=false;
int main()
{
  scanf("%d%d%d%d",&a,&b,&c,&n);
  if(a<n)//如果油量起始值小于目标值,当然不可能
    {
      cout<<"NO ANSWER!";
      return 0;
    }
  x.push(a);y.push(0);z.push(0);ans.push(0);//存入
  do//用do-while,那么至少会做一次,恰好也处理了初始状态等于目标状态的情况
    {
      int x1=x.front();
      int y1=y.front();
      int z1=z.front();
      int t=ans.front();
      if(x1==n||y1==n||z1==n)
    {
      flag=true;
      break;
    }//如果出现了目标状态,跳出循环
      if(x1>0)//如果1有油,就枚举1倒油的几种情况
    {
      if(g[x1-min(x1,b-y1)][y1+min(x1,b-y1)][z1]==0/*这个状态如果没有到过*/&&b-y1>0/*2可以倒出y1体积的油*/)
        {
          g[x1-min(x1,b-y1)][y1+min(x1,b-y1)][z1]=1;
          x.push(x1-min(x1,b-y1));
          y.push(y1+min(x1,b-y1));
          z.push(z1);//存入
          ans.push(t+1);//存步
        }
      //倒1->2
      if(g[x1-min(x1,c-z1)][y1][z1+min(x1,c-z1)]==0&&c-z1>0)
        {
          g[x1-min(x1,c-z1)][y1][z1+min(x1,c-z1)]=1;
          x.push(x1-min(x1,c-z1));
          y.push(y1);
          z.push(z1+min(x1,c-z1));
          ans.push(t+1);
        }//倒1->3
      if(g[0][y1][z1]==0)
        {
          g[0][y1][z1]=1;
          x.push(0);
          y.push(y1);
          z.push(z1);
          ans.push(t+1);
        }//倒空
    }
      if(y1>0)
    {
      if(g[x1][y1-min(y1,c-z1)][z1+min(y1,c-z1)]==0&&c-z1>0)
        {
          g[x1][y1-min(y1,c-z1)][z1+min(y1,c-z1)]=1;
          x.push(x1);
          y.push(y1-min(y1,c-z1));
          z.push(z1+min(y1,c-z1));
          ans.push(t+1);
        }//2->3
      if(g[x1+min(y1,a-x1)][y1-min(y1,a-x1)][z1]==0&&a-x1>0)
        {
          g[x1+min(y1,a-x1)][y1-min(y1,a-x1)][z1]=1;
          x.push(x1+min(y1,a-x1));
          y.push(y1-min(y1,a-x1));
          z.push(z1);
          ans.push(t+1);
        }//2->1
      if(g[x1][0][z1]==0)
        {
          g[x1][0][z1]=1;
          x.push(x1);
          y.push(0);
          z.push(z1);
          ans.push(t+1);
        }//倒完 
    }
      if(z1>0)
    {
      if(g[x1][y1+min(z1,b-y1)][z1-min(z1,b-y1)]==0&&b-y1>0)
        {
          g[x1][y1+min(z1,b-y1)][z1-min(z1,b-y1)]=1;
          x.push(x1);
          y.push(y1+min(z1,b-y1));
          z.push(z1-min(z1,b-y1));
          ans.push(t+1);
        }//3->1
      if(g[x1+min(z1,a-x1)][y1][z1-min(z1,a-x1)]==0&&a-x1>0)
        {
          g[x1+min(z1,a-x1)][y1][z1-min(z1,a-x1)]=1;
          x.push(x1+min(z1,a-x1));
          y.push(y1);
          z.push(z1-min(z1,a-x1));
          ans.push(t+1);
        }//3->2
      if(g[x1][y1][0]==0)
        {
          g[x1][y1][0]=1;
          x.push(x1);
          y.push(y1);
          z.push(0);
          ans.push(t+1);
        }//倒完不要了
    }
      ans.pop();
      x.pop();
      y.pop();
      z.pop();
    }while(!x.empty());//状态没有枚举完
  if(flag==true)
    printf("%d",ans.front());
  else
    cout<<"NO ANSWER!";
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值