非常可樂
大家一定覺的運動以後喝可樂是一件很愜意的事情,但是seeyou卻不這麼認爲。因爲每次當seeyou買了可樂以後,阿牛就要求和seeyou一起分享這一瓶可樂,而且一定要喝的和seeyou一樣多。但seeyou的手中只有兩個杯子,它們的容量分別是N 毫升和M 毫升 可樂的體積爲S (S<101)毫升 (正好裝滿一瓶) ,它們三個之間可以相互倒可樂 (都是沒有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聰明的ACMER你們說他們能平分嗎?如果能請輸出倒可樂的最少的次數,如果不能輸出"NO"。
Input
三個整數 : S 可樂的體積 , N 和 M是兩個杯子的容量,以"0 0 0"結束。
Output
如果能平分的話請輸出最少要倒的次數,否則輸出"NO"。
Sample Input
7 4 3
4 1 3
0 0 0
Sample Output
NO
3
題意:
三個杯子已知容量,只有一杯可樂,來回倒,問多少次能把可樂均分成兩份
題意很簡單的,關鍵是思路
思路:
倒的過程只有六種,即6個方向,要求的操作數類似於其他bfs要求的步數
把題中的s n m用數組存,來回倒的過程就能用裏外兩個循環寫,方便一點
純C的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int b[5];
struct node
{
int a[5];
int step;
} str[1005], x, y;
int vis[105][105][105];
void bfs(int s)
{
if(s%2!=0) printf("NO\n");
else if(b[1]==s/2) printf("1\n");
else
{
int i, j, in, out;
in = 0;
out = 0;
x.a[0] = s;
x.a[1] = 0;
x.a[2] = 0;
x.step = 0;
str[in++] = x;
while(in>out)
{
x = str[out++]; //得到最末尾的一個狀態
for(i=0; i<3; i++) //x.a[i]往外倒
{
if(x.a[i]==0) continue; //有的倒
for(j=0; j<3; j++) //x.a[j]往裏接
{
if(i==j) continue; //不能一個杯子操作!(一開始這裏也沒寫,樣例能過,但是代碼不對)
y = x;
if(x.a[i]+x.a[j] >= b[j]) //能倒滿
{ //注意裏面式子都是不能倒過來的
y.a[i] = x.a[i] + x.a[j] - b[j];
y.a[j] = b[j];
}
else //不能倒滿
{
y.a[j] = x.a[i] + x.a[j];
y.a[i] = 0;
}
if(vis[y.a[0]][y.a[1]][y.a[2]]==0) //如果這個狀態是新的,判斷+進隊列
{
y.step++;
if((y.a[0]==b[0]/2&&y.a[1]==b[0]/2) //一開始把判斷寫在判斷上面的x了,
//每次判斷最後一個,超時了。應該是得到一個狀態就判斷
//避免後知後覺做了一些無謂的動作
||(y.a[0]==b[0]/2&&y.a[2]==b[0]/2)
||(y.a[1]==b[0]/2&&y.a[2]==b[0]/2)
)
{
printf("%d\n", y.step);
return;
}
str[in++] = y;
vis[y.a[0]][y.a[1]][y.a[2]] = 1;
}
}
}
}
printf("NO\n");
}
}
int main()
{
while(~scanf("%d %d %d", &b[0], &b[1], &b[2]))
{
if(!b[0]&&!b[1]&&!b[2]) break;
memset(vis, 0, sizeof(vis));
vis[b[0]][0][0] = 1;
bfs(b[0]);
}
return 0;
}