【简单搜索】 HDU 1495 非常可乐 详解

这篇博客讨论了一个有趣的数学问题,涉及如何使用两个不同容量的杯子平分一瓶可乐。作者指出,如果可乐总量为奇数,则无法平分。然后,通过广度优先搜索算法(BFS)展示了如何在没有刻度的情况下找到最少倒水次数来平分可乐,如果可能的话。博客中提供了AC代码示例,并给出了多个测试用例以验证解决方案的正确性。
摘要由CSDN通过智能技术生成

非常可乐

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

 分析:

 首先如果S是奇数肯定不能平分。

 杯子是没有刻度的,所以杯子每一次倒水只有两种可能:

 ①把水全部倒给另一个杯子(如果另一个杯子装得下)

 ② 把另一个杯子倒满(如果另一个杯子装不下)

 而每次执行倒水有六种可能,即1杯向2杯倒水,1杯向3杯倒水,2向1,2向3,3向1,3向2倒水。相当于六个方向的广搜。

 AC代码:

  其实我写得有些繁琐了。

  S,N,M意义同题目,用s,n,m来记录三个杯子目前各有多少可乐。但这样写其实麻烦了好多,完全可以用一个数组coke[3]来代替,码量会少很多。

#include<string.h>
#include<queue>
#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
using namespace std;

int S,N,M;

typedef struct{
  int s,n,m;    //表示三个杯子各含多少可乐
  int step;
}node;

node vis[10000];
int cnt=0;

int bfs(node start){
    vis[cnt++]=start;
    queue<node>q;
    q.push(start);

    while(!q.empty()){
        node temp=q.front();
        q.pop();
        if(temp.m==S/2||temp.n==S/2||temp.s==S/2){//搜索终止条件
            int t=0;
            if(temp.m==S/2) t++;
            if(temp.n==S/2) t++;
            if(temp.s==S/2) t++;
            if(t==2)
               return temp.step;
            else //把剩下两杯还需要一步
               return temp.step+1;
        }

        for(int i=1;i<=6;i++){
            node new_node=temp;
            new_node.step++;
            int pour;

            if(i==1){
                pour=min(N-temp.n,temp.s);/*能倒多少可乐,由当前杯子的剩余可乐和另一个杯子能装下的可乐共同决定,取二者的最小值*/
                         
                new_node.s-=pour;
                new_node.n+=pour;
            }
            if(i==2)  {
                pour=min(M-temp.m,temp.s);
                new_node.s-=pour;
                new_node.m+=pour;
            }
            if(i==3)  {
                pour=min(S-temp.s,temp.n);
                new_node.n-=pour;
                new_node.s+=pour;
            }
            if(i==4)  {
                pour=min(M-temp.m,temp.n);
                new_node.n-=pour;
                new_node.m+=pour;
            }
            if(i==5)  {
                pour=min(S-temp.s,temp.m);
                new_node.m-=pour;
                new_node.s+=pour;
            }
            if(i==6)  {
                pour=min(N-temp.n,temp.m);
                new_node.m-=pour;
                new_node.n+=pour;
            }

            int flag=0;
            for(int j=0;j<cnt;j++){
                if(vis[j].m==new_node.m&&vis[j].n==new_node.n&&vis[j].s==new_node.s){
                    flag=1;
                    break;
                }

            }
            if(!flag&&pour){
                q.push(new_node);
                vis[cnt++]=new_node;
            }

        }
    }
    return -1;
}

int main()
{
    while(~scanf("%d%d%d",&S,&N,&M)&&S&&N&&M){
      memset(vis,0,sizeof(vis));
      cnt=0;
      if(S%2){
        printf("NO\n");
        continue;
      }
      node start;
      start.s=S;
      start.m=0;
      start.n=0;
      start.step=0;
      int ans=bfs(start);
      if(ans!=-1){
           printf("%d\n",ans);
      }
      else
           printf("NO\n");
    }
    return 0;
}

  测试数据:

4 1 3
3
3 2 1
NO
6 2 4
NO
4 2 2
1
13 6 7
NO
14 7 7
1
14 6 8
NO
14 5 9
13
100 42 58
49
100 82 18
49
26 12 14
NO
100 11 89
99
50 13 37
49
50 38 12
NO
50 15 35
9

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值