HDU 1459 M-非常可乐 //bfs倒水

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LMengi000/article/details/80547951

非常可乐

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


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
 
Recommend
LL   |   We have carefully selected several similar problems for you:   1175  1253  1072  1372  1180

题意:题目给出三个数据S,N,M,并且S==N+M; 问可乐是否能够平分,如果能够平分的话花,那么倒可乐的最少次数是多少,如果不能平分,那么就输出NO。

思路:有三个杯子倒水,无非就6种情况:s-->n,s-->m;n-->s,n-->m;m-->s,m-->n; 就这6种倒水的情况,我用号1、2、3来模拟三个杯子,双重循环来模拟倒水的杯子还互相之间倒水的这6种状态,而且每一次倒水的时候都是从最初始状态开始倒,

sign数组来标记倒水的状态:从某一初始状态开始,模拟杯子之间的倒水过程,用sign标记,来避免有重复的倒水状态被多记录次数和被推入队列。

pour函数来模拟倒水的过程:模拟的是a往b种倒水,下标代表倒水的杯子;如果总共的水量sum是>=b杯的,那么就把谁倒入b杯中,剩下的水还是在a杯中;如果总共的水量sum是<b的,那么就把全部的水都倒入b杯中,然后a杯就空了。

当达到能够平分的条件时,就输出倒水的次数。

这一个题目还有一个类似的题目倒水还要输出路径链接

但是对于这个题目,我理解的还是不够透彻,不够深刻,不太明白为什么在main函数中,要先把2、3杯子排序,有的说这样是为了方便bfs判断的条件


#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int v[5];
int sign[110][110][100];
struct cup//记录遍历中3个水杯容藏可乐情况
{
    int v[5];
    int step;
}temp;

void pour(int a,int b)//倒水函数,把a杯子中的可乐倒到b杯子中
{
    int sum=temp.v[a]+temp.v[b];
    if(sum>=v[b])//能把b杯倒满,剩下的还是在a杯 
        temp.v[b]=v[b];
    else
        temp.v[b]=sum;//全部倒入b杯中 ,那么a杯中就为 0了 
    temp.v[a]=sum-temp.v[b];
}

void bfs()
{
    int i,j;
    queue<cup>q;
    cup cnt;
    cnt.v[1]=v[1]; //给水杯赋初值 
    cnt.v[2]=0;
    cnt.v[3]=0;
    cnt.step=0;
    q.push(cnt);
    memset(sign,0,sizeof(sign));
    sign[v[1]][0][0]=1; //赋值之后并标记,代表这一种情况已经有过了 
    while(!q.empty())
    {
        cnt=q.front();
        q.pop();
        if(cnt.v[1]==cnt.v[3]&&cnt.v[2]==0)
        {
            printf("%d\n",cnt.step);
            return ;
        }
        for(i=1;i<4;++i)
        {
            for(j=1;j<4;++j)
            {
                if(i!=j)//自己不倒水给自己
                {
                    temp=cnt;//每个水位情况都要把所有操作枚举一遍,所以都要赋值为原始水位情况
                    pour(i,j);//倒水i倒往j,这一函数就是来模拟倒水的过程 
                    printf("temp.v[1]=%d temp.v[2]=%d temp.v[3]=%d\n",temp.v[1],temp.v[2],temp.v[3]); 
                    if(!sign[temp.v[1]][temp.v[2]][temp.v[3]]) //如果这一种倒水情况还没有倒过,那么就把这一种情况标记,然后再做以下操作 
                    {
                        temp.step++;
                        q.push(temp);
                        sign[temp.v[1]][temp.v[2]][temp.v[3]]=1;
                    }
                }
            }
        }
    }
    printf("NO\n");
}

int main()
{
    while(scanf("%d%d%d",&v[1],&v[2],&v[3])&&v[1]||v[2]||v[3])
    {
        if(v[2]>v[3])
        {
            int t=v[2];
            v[2]=v[3];
            v[3]=t;
        }
        bfs();
    }
    return 0;
}




猜你喜欢

转载自blog.csdn.net/LMengi000/article/details/80547951