HDU 1495 非常可乐

题目链接 HDU 1495

非常可乐

                                                                     Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
                                                                                       Total Submission(s): 7219    Accepted Submission(s): 2878


Problem Description
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是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
 

Author
seeyou
 

Source
“2006校园文化活动月”之“校庆杯”大学生程序设计竞赛暨杭州电子科技大学第四届大学生程序设计竞赛
 

分析:

广搜,由于水杯没有标识,用杯子 x 给 y 倒可乐时必须一直持续把 y 倒满或者把 x 倒空,不能中途停止。

我们用结构体记录每次倒水的状态,保存在队列中,用 vis 数组标记状态,这里只用二维就够了(想一想为什么)。


代码:

#include 
#include 
#include 
#include 
using namespace std;
int vis[105][105];
struct cup
{
    int c[3];   //c[0] 表示可乐瓶,c[1],c[2] 表示两个杯子
    int cnt;    //cnt 表示倒的次数
};
cup Cur, Next;  //当前状态和下一个状态
queue Q;
int s[4];   //s[0],s[1],s[2]分别表示瓶子,两个杯子的容积

void solve(int x, int y)        //从 x 向 y 倒可乐
{
    Next.c[3 - x - y] = Cur.c[3 - x - y];   //剩下那个不变
    Next.cnt = Cur.cnt + 1;
    if(Cur.c[x] >= s[y] - Cur.c[y])     //将 y 倒满
    {
        Next.c[x] = Cur.c[x] - (s[y] - Cur.c[y]);
        Next.c[y] = s[y];
        if(!vis[Next.c[0]][Next.c[1]])      //此状态还未出现
            Q.push(Next);                   //进队列
        vis[Next.c[0]][Next.c[1]] = 1;      //标记
    }
    else                //将 x 倒空
    {
        Next.c[x] = 0;
        Next.c[y] = Cur.c[y] + Cur.c[x];
        if(!vis[Next.c[0]][Next.c[1]])
            Q.push(Next);
        vis[Next.c[0]][Next.c[1]] = 1;
    }
}

int bfs()
{
    while(!Q.empty()) Q.pop();  //先将队列清空
    Cur.c[0] = s[0];            //初始状态
    Cur.c[1] = Cur.c[2] = 0;
    Cur.cnt = 0;
    Q.push(Cur);
    vis[s[0]][0] = 1;
    while(!Q.empty())
    {
        Cur = Q.front();
        Q.pop();
        int sum = 0;            //判断是否平分
        for(int i = 0; i < 3; i++)
            if(Cur.c[i] == s[0] / 2)
            {
                sum++;
            }
        if(sum == 2)        //已经平分可乐,返回次数
        {
            return Cur.cnt;
        }
        if(Cur.c[0] != 0)   //0 有可乐
        {
            solve(0, 1);    //向 1 倒
            solve(0, 2);    //向 2 倒
        }
        if(Cur.c[1] != 0)
        {
            solve(1, 0);
            solve(1, 2);
        }
        if(Cur.c[2] != 0)
        {
            solve(2, 0);
            solve(2, 1);
        }
    }
    return -1;          //不能平分
}

int main()
{
    while(~scanf("%d%d%d", &s[0], &s[1], &s[2]))
    {
        if(s[0] + s[1] + s[2] == 0) break;
        memset(vis, 0, sizeof(vis));
        if(s[0] % 2 == 1)       //可乐为奇数,不能平分
        {
            printf("NO\n");
            continue;
        }
        int k = bfs();
        if(k == -1) printf("NO\n");
        else printf("%d\n", k);
    }
    return 0;
}




你可能感兴趣的:(BFS)