NYOJ-21-三个水杯
描述
给出三个水杯,大小不一,并且只有最大的水杯的水是装满的,其余两个为空杯子。三个水杯之间相互倒水,并且水杯没有标识,只能根据给出的水杯体积来计算。现在要求你写出一个程序,使其输出使初始状态到达目标状态的最少次数。
输入
第一行一个整数N(0< N <50)表示N组测试数据
接下来每组测试数据有两行,第一行给出三个整数V1 V2 V3 (V1>V2>V3 V1<100 V3>0)表示三个水杯的体积。
第二行给出三个整数E1 E2 E3 (体积小于等于相应水杯体积)表示我们需要的最终状态
输出
每行输出相应测试数据最少的倒水次数。如果达不到目标状态输出-1
样例输入
2
6 3 1
4 1 1
9 3 2
7 1 1
样例输出
3
-1
这是一道经典的bfs,虽然代码篇幅很长,但是原理很简单,也容易理解。
#include <stdio.h>
typedef struct State
{
int Ei;
int Ej;
int Ek;
int Step;
} State;
State S[5050];
int V1, V2, V3;
int E1, E2, E3;
int head, tail;
void init()
{
S[0].Ei = V1;
S[0].Ej = 0;
S[0].Ek = 0;
S[0].Step = 0;
head = 0;
tail = 1;
}
int haveSame()
{
int i;
for (i = 0; i < tail; i++)
{
if (S[i].Ei == S[tail].Ei && S[i].Ej == S[tail].Ej && S[i].Ek == S[tail].Ek)
{
return 1;
}
}
return 0;
}
int judge(int Ei, int Ej, int Ek, int Step)
{
if (Ei == E1 && Ej == E2 && Ek == E3)
{
printf("%d\n", Step);
return 1;
}
return 0;
}
//BFS
void solve()
{
if (judge(S[0].Ei, S[0].Ej, S[0].Ek, S[0].Step))
{
return ;
}
while (head < tail)
{
if (S[head].Ei > 0)
{
//第一个杯子往第二个杯子里倒
if (S[head].Ej < V2)
{
S[tail].Ek = S[head].Ek;
S[tail].Ej = S[head].Ei > V2 - S[head].Ej ? V2 : S[head].Ei + S[head].Ej;
S[tail].Ei = S[head].Ei > V2 - S[head].Ej ? S[head].Ei - V2 + S[head].Ej : 0;
S[tail].Step = S[head].Step + 1;
if (judge(S[tail].Ei, S[tail].Ej, S[tail].Ek, S[tail].Step))
{
return ;
}
if (!haveSame())
{
tail++;
}
}
//第一个杯子往第三个杯子里倒
if (S[head].Ek < V3)
{
S[tail].Ej = S[head].Ej;
S[tail].Ek = S[head].Ei > V3 - S[head].Ek ? V3 : S[head].Ei + S[head].Ek;
S[tail].Ei = S[head].Ei > V3 - S[head].Ek ? S[head].Ei - V3 + S[head].Ek : 0;
S[tail].Step = S[head].Step + 1;
if (judge(S[tail].Ei, S[tail].Ej, S[tail].Ek, S[tail].Step))
{
return ;
}
if (!haveSame())
{
tail++;
}
}
}
if (S[head].Ej > 0)
{
//第二个杯子往第一个杯子里倒
if (S[head].Ei < V1)
{
S[tail].Ek = S[head].Ek;
S[tail].Ei = S[head].Ej > V1 - S[head].Ei ? V1 : S[head].Ej + S[head].Ei;
S[tail].Ej = S[head].Ej > V1 - S[head].Ei ? S[head].Ej - V1 + S[head].Ei : 0;
S[tail].Step = S[head].Step + 1;
if (judge(S[tail].Ei, S[tail].Ej, S[tail].Ek, S[tail].Step))
{
return ;
}
if (!haveSame())
{
tail++;
}
}
//第二个杯子往第三个杯子里倒
if (S[head].Ek < V3)
{
S[tail].Ei = S[head].Ei;
S[tail].Ek = S[head].Ej > V3 - S[head].Ek ? V3 : S[head].Ej + S[head].Ek;
S[tail].Ej = S[head].Ej > V3 - S[head].Ek ? S[head].Ej - V3 + S[head].Ek : 0;
S[tail].Step = S[head].Step + 1;
if (judge(S[tail].Ei, S[tail].Ej, S[tail].Ek, S[tail].Step))
{
return ;
}
if (!haveSame())
{
tail++;
}
}
}
if (S[head].Ek > 0)
{
//第三个杯子往第一个杯子里倒
if (S[head].Ei < V1)
{
S[tail].Ej = S[head].Ej;
S[tail].Ei = S[head].Ek > V1 - S[head].Ei ? V1 : S[head].Ek + S[head].Ei;
S[tail].Ek = S[head].Ek > V1 - S[head].Ei ? S[head].Ek - V1 + S[head].Ei : 0;
S[tail].Step = S[head].Step + 1;
if (judge(S[tail].Ei, S[tail].Ej, S[tail].Ek, S[tail].Step))
{
return ;
}
if (!haveSame())
{
tail++;
}
}//第三个杯子往第二个杯子里倒
if (S[head].Ej < V2)
{
S[tail].Ei = S[head].Ei;
S[tail].Ej = S[head].Ek > V2 - S[head].Ej ? V2 : S[head].Ek + S[head].Ej;
S[tail].Ek = S[head].Ek > V2 - S[head].Ej ? S[head].Ek - V2 + S[head].Ej : 0;
S[tail].Step = S[head].Step + 1;
if (judge(S[tail].Ei, S[tail].Ej, S[tail].Ek, S[tail].Step))
{
return ;
}
if (!haveSame())
{
tail++;
}
}
}
head++;
}
printf("-1\n");
return ;
}
int main()
{
int N;
scanf("%d", &N);
while (N--)
{
scanf("%d %d %d", &V1, &V2, &V3);
scanf("%d %d %d", &E1, &E2, &E3);
init();
solve();
}
return 0;
}
最开始写这个代码时,因为忽略了一种情况,而WA了两遍。
比如说,
9 7 5
9 0 0
这需要倒的次数为0,直接进行初始条件的判断后即可输出结果为0,然而因为我缺乏对初始条件的判断,所以导致结果为2,有些可悲,一失足成千古恨。当然,加上这个初始条件的判断后,顺利AC了……