首页 > 代码库 > 三个水杯吧!

三个水杯吧!

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


三个水杯吧!