BFS,隐式图的遍历。
/**
**author :Skylon **
╭︿︿︿╮
{/ A C /}
( (OO) )
︶︶︶
** **
**NYOJ_21题**
** 2014 年 7月 18日**
**/
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cctype>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
struct CUP//用一个结构体来表示三个水杯的状态,三个水杯分别标记为0、1、2,step为所需要操作的次数。
{
int a[3];
int step;
}cup,s,e;//s为起始状态,e为目标状态
bool flag[110][110][110];//用来标记水杯的状态,虽然是三维的,但是不要在意这些细节,作用就是标记而已,因为有三个杯子,所以是三维的。如果题目是四个水杯...
int dir[6][2]=
{
0,1, //把0杯中的水倒入1杯
0,2, //把0杯中的水倒入2杯
1,0, //把1杯中的水倒入0杯
1,2, //把1杯中的水倒入2杯
2,0, //把2杯中的水倒入0杯
2,1 //把2杯中的水倒入1杯
};//这是搜索的方向,一共有6个。其实本没有方向,只是将倒水的过程抽象化了。三个水杯,每次只能选择其中的两个水杯来进行倒水操作,当然就有6种倒水方式。在给三个水杯标记为0、1、2这三个号之后,就用0,1表示把编号为0的水杯中的水倒入编号为1的水杯中。
int del(CUP &p,int x,int y)//用来模拟倒水过程,在三个水杯的p状态下,将这个状态下编号为x的水杯中的水到入编号为y的水杯中。注意<span style="font-family: Arial, Helvetica, sans-serif;">CUP &p</span>
{
if (p.a[x]==0||p.a[y]==s.a[y])//因为是将x倒入y中。所以,如果x杯中没有水或是y杯中的水满了,就不能倒水了
return 0;
else//把x被中的水倒入y杯中,只有两种情况
{
if (p.a[x]+p.a[y]<=s.a[y])//x杯中的水能全部倒入y杯中
{
p.a[y]+=p.a[x]; //注意
p.a[x]=0; //注意
}
else//x杯中的水不能全部倒入y杯中
{
p.a[x]-=(s.a[y]-p.a[y]); //注意
p.a[y]=s.a[y]; //注意
}//注意上面两个模拟过程中的顺序不能交换
if (flag[p.a[0]] [p.a[1]] [p.a[2]]==false)//标记状态,并返回。模拟倒水过程成功。
{
flag[p.a[0]][p.a[1]][p.a[2]]=true;
return 1;
}
}
}
int bfs()//广搜
{
CUP cup;//定义初始节点,状态初始化
cup.a[0]=s.a[0];//开始的时候只有最大的水杯中装满水
cup.a[1]=cup.a[2]=cup.step=0;//其余的两个水杯中没有水,且初始操作数位01
queue<CUP>v;
v.push(cup);
flag[cup.a[0]][cup.a[1]][cup.a[2]]=true;//标记初始状态
while (!v.empty())
{
CUP now=v.front();
v.pop();
if (now.a[0]==e.a[0]&&now.a[1]==e.a[1]&&now.a[2]==e.a[2])//当bfs到目标状态时就...
return now.step;
for (int i=0;i<6;i++)//向六个方向搜索
{
CUP pre=now;
if (del(pre,dir[i][0],dir[i][1]))
{
pre.step=now.step+1;
v.push(pre);
}
}
}
return -1;//没有到达终点就-1咯
}
int main()
{
int n;
scanf("%d",&n);
while (n--)
{
cin>>s.a[0]>>s.a[1]>>s.a[2]>>e.a[0]>>e.a[1]>>e.a[2];//读入起点和终点
memset(flag,0,sizeof(flag));
printf("%d\n",bfs());
}
return 0;
}