非常可乐 HDU - 1495 (BFS + 模拟倒水过程 OR 数论)

传送门

非常可乐

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

 

题解:这一题难点儿的都在不好想,尤其是搜索时候的模拟过程(即相互倒水的过程),想会这点儿基本上就能做了,但是有一点,标记数组vis别开大,不然就 TE , 我开的是vis[109][109][109] TE 了,换成vis[105][105][105]过了,虽然卡着时间过去的

先来看一下搜索的代码:

#include
#include
#include
#include
#include
using namespace std;
int s[3] , vis[105][105][105];

struct cup{
  int c[3] , step;
}now;

int bfs(){
  queue q ;
  now.c[0] = s[0] ,now.c[1] = 0 , now.c[2] = 0 , now.step = 0;
  vis[now.c[0]][now.c[1]][now.c[2]] = 1;
  q.push(now);
  while(!q.empty()){
    now = q.front();
    if((now.c[0] == now.c[1] && now.c[2] == 0) || (now.c[0] == now.c[2] && now.c[1] == 0) || (now.c[1] == now.c[2] && now.c[0] == 0))
    //判断终止条件,即有一个杯子是空,另外两个杯子一样多
    {
      return now.step;
    }
    q.pop();
    for(int i = 0 ; i < 3 ; i ++){
      //模拟倒水的 6 种情况 a 倒 b,c  ||  b倒 a , c   || c 倒 a , b
        for(int j = 0 ; j < 3 ; j ++){
        if(i != j){ // 非自己倒给自己的过程,即其他的倒水过程
          int k = s[j] - now.c[j];
          if(k > now.c[i]){
            k = now.c[i];
          }
          cup next = now;
          //第 i 杯往第 j 杯里倒水过程
          next.c[i] = now.c[i] - k;
          next.c[j] = now.c[j] + k;
          next.step = now.step + 1;
          if(vis[next.c[0]][next.c[1]][next.c[2]] == 0){
            vis[next.c[0]][next.c[1]][next.c[2]] = 1;
            q.push(next);
          }
        }
      }
    }
  }
  return -1;
}

int main(){
  while(cin >> s[0] >> s[1] >> s[2] && s[0] + s[1] + s[2]){
    memset(vis,0,sizeof(vis));
    if(s[0] != s[1] + s[2]){
      printf("NO\n");
      break;
    }
    else{
      int ans = bfs();
      if(ans == -1)
        printf("NO\n");
      else
        printf("%d\n",ans);
    }
  }
  return 0 ;
}

 

还有一种数论的做法,可以参考一下https://blog.csdn.net/V5ZSQ/article/details/52097459这位大佬的讲解很详细,望对你们有帮助,

附上数论代码;

#include
#include
#include
using namespace std;
int main(){
  int a , b , c;
  while(cin >> a >> b >> c && (a + b + c)){
    a /= __gcd(b,c);
    if(a & 1)
      cout<<"NO\n";
    else
      cout<< a-1 <

 

你可能感兴趣的:(搜索,比赛试手)