你在河边。给你一个m升的水壶和一个n升的水壶,其中0 < m < n 。两个水壶最初都是空的。水壶没有标记以允许测量较小的数量。您必须使用水罐来测量 d 升水,其中 d < n。确定在其中一个水壶中获得 d 升水所需执行的最少操作次数。
您可以执行的操作是:
- 清空水壶
- 装满一壶
- 将水从一个罐子倒入另一个罐子,直到其中一个罐子是空的或满的。
有几种方法可以解决这个问题,包括 BFS 和 DP。在本文中,讨论了解决该问题的算术方法。该问题可以通过形式为 mx + ny = d 的丢番图方程建模,该方程可解当且仅当 gcd(m, n) 除以 d。此外,可以使用 GCD 的扩展欧几里德算法给出满足方程的解 x,y。
例如,如果我们有一个 5 升的水罐 J1 (n = 5) 和另一个 3 升的水罐 J2 (m = 3),我们必须用它们来测量 1 升的水。相关的方程将是 5n + 3m = 1。首先,这个问题可以解决,因为 gcd(3,5) = 1 将 1 整除(请参阅此处了解详细说明)。使用扩展欧几里德算法,我们得到满足方程的 n 和 m 值,即 n = 2 和 m = -3。 n, m 的这些值也有一些含义,比如这里 n = 2 和 m = -3 意味着我们必须填充 J1 两次并清空 J2 三次。
现在要找到最少要执行的操作数,我们必须决定应该先装满哪个水壶。根据选择装满哪个壶和清空哪个壶,我们有两种不同的解决方案,其中最小的就是我们的答案。
解决方案 1(始终从 m 升水壶倒入 n 升水壶)
- 将 m 升罐装满,然后倒入 n 升罐中。
- 每当 m 升水壶变空时,将其装满。
- 每当 n 升水罐装满时,它就会倒空。
- 重复步骤 1、2、3,直到 n 升水壶或 m 升水壶装有 d 升水。
步骤 1、2 和 3 中的每一步都算作我们执行的一个操作。假设算法 1 在 C1 次操作中完成了任务。
解决方案 2(总是从 n 升水壶倒入 m 升水壶)
- 将 n 升水壶装满,然后倒入 m 升水壶。
- 每当 n 升水壶变空时,将其装满。
- 每当 m 升水罐装满时,它就会倒空。
- 重复步骤 1、2 和 3,直到 n 升水壶或 m 升水壶装有 d 升水。
假设解决方案 2 在 C2 操作中完成了任务。
现在我们的最终解决方案将是 C1 和 C2 的最小值。
现在我们说明这两种解决方案的工作原理。假设有一个 3 升的水壶和一个 5 升的水壶来测量 4 升水,因此m = 3,n = 5 和 d = 4 。相关的丢番图方程将为 3m + 5n = 4。我们使用 (x, y) 对分别表示每个浇注步骤中 3 升壶和 5 升壶内的水量。
使用解决方案 1,连续浇注步骤为:
(0,0)->(3,0)->(0,3)->(3,3)->(1,5)->(1,0)->(0,1)->(3,1)->(0,4)
因此,您需要执行的操作数为8。
使用解决方案 2,连续浇注步骤为:
(0,0)->(0,5)->(3,2)->(0,2)->(2,0)->(2,5)->(3,4)
因此,您需要执行的操作数为6。
因此,我们将使用解决方案 2 在 6 次操作或移动中测量 4 升水。
基于这里的解释是实现。
C++
// C++ program to count minimum number of steps
// required to measure d litres water using jugs
// of m liters and n liters capacity.
#include
using namespace std;
// Utility function to return GCD of 'a'
// and 'b'.
int gcd(int a, int b)
{
if (b==0)
return a;
return gcd(b, a%b);
}
/* fromCap -- Capacity of jug from which
water is poured
toCap -- Capacity of jug to which
water is poured
d -- Amount to be measured */
int pour(int fromCap, int toCap, int d)
{
// Initialize current amount of water
// in source and destination jugs
int from = fromCap;
int to = 0;
// Initialize count of steps required
int step = 1; // Needed to fill "from" Jug
// Break the loop when either of the two
// jugs has d litre water
while (from != d && to != d)
{
// Find the maximum amount that can be
// poured
int temp = min(from, toCap - to);
// Pour "temp" liters from "from" to "to"
to += temp;
from -= temp;
// Increment count of steps
step++;
if (from == d || to == d)
break;
// If first jug becomes empty, fill it
if (from == 0)
{
from = fromCap;
step++;
}
// If second jug becomes full, empty it
if (to == toCap)
{
to = 0;
step++;
}
}
return step;
}
// Returns count of minimum steps needed to
// measure d liter
int minSteps(int m, int n, int d)
{
// To make sure that m is smaller than n
if (m > n)
swap(m, n);
// For d > n we cant measure the water
// using the jugs
if (d > n)
return -1;
// If gcd of n and m does not divide d
// then solution is not possible
if ((d % gcd(n,m)) != 0)
return -1;
// Return minimum two cases:
// a) Water of n liter jug is poured into
// m liter jug
// b) Vice versa of "a"
return min(pour(n,m,d), // n to m
pour(m,n,d)); // m to n
}
// Driver code to test above
int main()
{
int n = 3, m = 5, d = 4;
printf("Minimum number of steps required is %d",
minSteps(m, n, d));
return 0;
}
Java
// Java program to count minimum number of
// steps required to measure d litres water
// using jugs of m liters and n liters capacity.
import java.io.*;
class GFG{
// Utility function to return GCD of 'a'
// and 'b'.
public static int gcd(int a, int b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
/* fromCap -- Capacity of jug from which
water is poured
toCap -- Capacity of jug to which
water is poured
d -- Amount to be measured */
public static int pour(int fromCap, int toCap,
int d)
{
// Initialize current amount of water
// in source and destination jugs
int from = fromCap;
int to = 0;
// Initialize count of steps required
int step = 1; // Needed to fill "from" Jug
// Break the loop when either of the two
// jugs has d litre water
while (from != d && to != d)
{
// Find the maximum amount that can be
// poured
int temp = Math.min(from, toCap - to);
// Pour "temp" liters from "from" to "to"
to += temp;
from -= temp;
// Increment count of steps
step++;
if (from == d || to == d)
break;
// If first jug becomes empty, fill it
if (from == 0)
{
from = fromCap;
step++;
}
// If second jug becomes full, empty it
if (to == toCap)
{
to = 0;
step++;
}
}
return step;
}
// Returns count of minimum steps needed to
// measure d liter
public static int minSteps(int m, int n, int d)
{
// To make sure that m is smaller than n
if (m > n)
{
int t = m;
m = n;
n = t;
}
// For d > n we cant measure the water
// using the jugs
if (d > n)
return -1;
// If gcd of n and m does not divide d
// then solution is not possible
if ((d % gcd(n, m)) != 0)
return -1;
// Return minimum two cases:
// a) Water of n liter jug is poured into
// m liter jug
// b) Vice versa of "a"
return Math.min(pour(n, m, d), // n to m
pour(m, n, d)); // m to n
}
// Driver code
public static void main(String[] args)
{
int n = 3, m = 5, d = 4;
System.out.println("Minimum number of " +
"steps required is " +
minSteps(m, n, d));
}
}
// This code is contributed by RohitOberoi
Python3
# Python3 implementation of program to count
# minimum number of steps required to measure
# d litre water using jugs of m liters and n
# liters capacity.
def gcd(a, b):
if b==0:
return a
return gcd(b, a%b)
''' fromCap -- Capacity of jug from which
water is poured
toCap -- Capacity of jug to which
water is poured
d -- Amount to be measured '''
def Pour(toJugCap, fromJugCap, d):
# Initialize current amount of water
# in source and destination jugs
fromJug = fromJugCap
toJug = 0
# Initialize steps required
step = 1
while ((fromJug is not d) and (toJug is not d)):
# Find the maximum amount that can be
# poured
temp = min(fromJug, toJugCap-toJug)
# Pour 'temp' liter from 'fromJug' to 'toJug'
toJug = toJug + temp
fromJug = fromJug - temp
step = step + 1
if ((fromJug == d) or (toJug == d)):
break
# If first jug becomes empty, fill it
if fromJug == 0:
fromJug = fromJugCap
step = step + 1
# If second jug becomes full, empty it
if toJug == toJugCap:
toJug = 0
step = step + 1
return step
# Returns count of minimum steps needed to
# measure d liter
def minSteps(n, m, d):
if m> n:
temp = m
m = n
n = temp
if (d%(gcd(n,m)) is not 0):
return -1
# Return minimum two cases:
# a) Water of n liter jug is poured into
# m liter jug
return(min(Pour(n,m,d), Pour(m,n,d)))
# Driver code
if __name__ == '__main__':
n = 3
m = 5
d = 4
print('Minimum number of steps required is',
minSteps(n, m, d))
# This code is contributed by Sanket Badhe
Javascript
输出:
Minimum number of steps required is 6
另一个详细解释:http://web.mit.edu/neboat/Public/6.042/numbertheory1.pdf
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。