三个水杯
时间限制:1000 ms | 内存限制:65535 KB
难度:4
描述
给出三个水杯,大小不一,并且只有最大的水杯的水是装满的,其余两个为空杯子。三个水杯之间相互倒水,并且水杯没有标识,只能根据给出的水杯体积来计算。现在要求你写出一个程序,使其输出使初始状态到达目标状态的最少次数。
输入
第一行一个整数N(0
输出
每行输出相应测试数据最少的倒水次数。如果达不到目标状态输出-1
样例输入
2
6 3 1
4 1 1
9 3 2
7 1 1
样例输出
3
-1
思路
既然是找最少的次数,那就使用广搜,把当前状态每一个可以互相倒水且不与之前重复的状态放入队列中,每次取对首元素时判断是否为最终状态,不是的话继续放。如果取到队空则说明达不到目标返回-1
代码如下
#include <iostream>
#include <stdio.h>
#include <map>
#include <queue>
using namespace std;
int m[3];
int z_m[3];
struct zhuang_tai{
int L[3];
int sum;
bool operator < (const zhuang_tai &a)const ///重载<运算符用于结构体排序
{
if(a.L[0]==L[0])
if(a.L[1]==L[1])
if(a.L[2]==L[2]);
else
return a.L[2]<L[2];
else
return a.L[1]<L[1];
return a.L[0]<L[0];
}
}ans,k;
queue<zhuang_tai>q;
map<zhuang_tai,int>mp;
int pan(zhuang_tai a) ///判断是否与目标状态相同
{
if(a.L[0]==z_m[0]&&a.L[2]==z_m[2]&&a.L[1]==z_m[1])
return 1;
return 0;
}
void swp(int a ,int b,int c)
{
zhuang_tai ans1;
if(ans.L[a]<(m[b]-ans.L[b]))///如果第一个杯子水小于要倒的杯子剩余容量就全部倒到第二个杯子
{
ans1.L[a]=0;
ans1.L[b]=ans.L[b]+ans.L[a];
}
else ///否则把第二个杯子倒满
{
ans1.L[a]=ans.L[a]-(m[b]-ans.L[b]);
ans1.L[b]=m[b];
}
ans1.L[c]=ans.L[c];
ans1.sum=0;
if(!mp.count(ans1)) ///判断三种杯子状态是否出现过,如果没有出现过就入队
{
mp[ans1]++;
ans1.sum=ans.sum+1;
q.push(ans1);
}
}
int main()
{
int w;cin>>w;
while(w--)
{
while(!q.empty())
q.pop();
mp.clear();
cin>>m[0]>>m[1]>>m[2];
cin>>z_m[0]>>z_m[1]>>z_m[2];
ans.L[0]=m[0];
ans.L[1]=0;
ans.L[2]=0;
ans.sum=0;
q.push(ans);
int summ=0;
while(!q.empty())
{
ans=q.front();
summ++;
q.pop();
if(pan(ans)) ///判断是否与目标状态相同
{
cout<<ans.sum<<endl;
goto go; ///跳过输出-1的情况
}
swp(0,1,2); ///六种相互倒的状态
swp(0,2,1);
swp(1,0,2);
swp(1,2,0);
swp(2,1,0);
swp(2,0,1);
}
cout<<-1<<endl;
go:;
}
return 0;
}