你在河边。给您一个m升的水罐和一个n升的水罐,其中0
- 倒空一壶
- 装满水罐
- 将水从一个水罐倒入另一个水罐,直到其中一个水罐倒空或装满。
解决此问题的方法有多种,包括BFS和DP。在本文中,讨论了一种解决该问题的算术方法。可以通过形式为mx + ny = d的Diophantine方程对问题进行建模,当且仅当gcd(m,n)除以d时,该方程才可解决。同样,可以使用用于GCD的扩展Euclid算法来给出满足方程式的解x,y。
例如,如果我们有一个5升的水罐J1(n = 5)和另一个3升的水罐J2(m = 3),我们必须使用它们来量取1升的水。关联的等式为5n + 3m =1。首先,由于gcd(3,5)= 1除以1(因此请参见详细说明),因此可以解决此问题。使用扩展Euclid算法,我们得到满足方程的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
输出:
Minimum number of steps required is 6
另一个详细说明:http://web.mit.edu/neboat/Public/6.042/numbertheory1.pdf