2022.11.29.非常可乐HDU - 1495

博客讨论了一道算法题目,涉及如何通过杯子间的倒水操作平分可乐。两种解题思路分别是使用广度优先搜索(BFS)和数论方法。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"。

Sample

InputcopyOutputcopy
 
7 4 3 4 1 3 0 0 0
 
NO 
3

原题链接:传送门

这道题思路分别有两种角度一种是bfs另一种就是

bfs思路:这道题非常适合bfs爆搜去做,因为要平分可乐,所以s必须为偶数

我们很容易可以想到,总共有6种倒可乐的操作分别是1->2,1->3,2->1,2->3,3->1,3->2.

另外就是一点小细节:通过在三个杯子倒可乐,达到有两个杯子平分所有可乐的目的,所以最后平分出的两个杯子可以是三个中任意两个,所以我们在处理的时候要把最大的两个杯子放在前面,s=n+m,其实转化过来就是平分s,那么除了n=m不然不可能使杯子n和杯子m平分s,所以我们用n = max(n,m)和s,则一定可以在s中平分出来,这样处理我们只需要通过判断tt.s == tt.n&&tt.m == 0即可,否则便需要判断(tt.s==n&&tt.m==0)||(tt.s==tt.m&&tt.n==0)||(tt.n==tt.m&&tt.s==0),因为不知道哪两个杯子平分了可乐,所以要都判断一下。

bfs-AC代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
int S, N, M;
struct node{
	int s, n, m, step;
} t, tt;
bool vis[MAXN][MAXN][MAXN]; //判断当前操作是否进行过
int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  while (cin >> S >> N >> M, N or M or S){
	if (S & 1){
      cout << "NO" << "\n";
	  continue;
    }
	memset(vis, 0, sizeof vis);
	if (N < M) swap(N, M); //保证最大的两个杯子在前面
	int ans = -1, f = 0;
	node x = {S, 0, 0, 0};
	queue<node> q;
	q.push(x);
	vis[S][0][0] = 1;
	while (!q.empty()){
	  auto t = q.front();
	  q.pop();
	  if (t.s == t.n && !t.m){
	    f = 1, ans = t.step;break;
	  }
	  for (int i = 0; i < 6; i++){
/*1->2*/if (i == 0) tt = (t.s + t.n <= N) ? (node{0, t.s + t.n, t.m}) : (node{t.s + t.n - N, N, t.m});
/*1->3*/else if (i == 1) tt = (t.s + t.m <= M) ? (node{0, t.n, t.s + t.m}) : (node{t.s + t.m - M, t.n, M});
/*2->1*/else if (i == 2) tt = (t.s + t.n <= S) ? (node{t.s + t.n, 0, t.m}) : (node{S, t.s + t.n - S, t.m});
/*2->3*/else if (i == 3) tt = (t.n + t.m <= M) ? (node{t.s, 0, t.n + t.m}) : (node{t.s, t.n + t.m - M, M});
/*3->1*/else if (i == 4) tt = (t.s + t.m <= S) ? (node{t.s + t.m, t.n, 0}) : (node{S, t.n, t.s + t.m - S});
/*3->2*/else if (i == 5) tt = (t.n + t.m <= N) ? (node{t.s, t.m + t.n, 0}) : (node{t.s, N, t.n + t.m - N});
		if (!vis[tt.s][tt.n][tt.m]) tt.step = t.step + 1, vis[tt.s][tt.n][tt.m] = 1, q.push(tt);
      }
    }
    if (!f) cout << "NO\n";
    else cout << ans << "\n";
  }
  return 0;
}

数论思路:最后可以发现这道题能用数论秒杀,打表还是能发现规律的

数论-AC代码:

#include <bits/stdc++.h>
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" << endl;
	else cout << a - 1 << endl;
  }
  return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值