📜  两个水壶拼图

📅  最后修改于: 2021-09-17 07:02:52             🧑  作者: Mango

你在河边。给你一个m升的水壶和一个n升的水壶,其中0 < m < n 。两个水壶最初都是空的。水壶没有标记以允许测量较小的数量。您必须使用水罐来测量 d 升水,其中 d < n。确定在其中一个水壶中获得 d 升水所需执行的最少操作次数。
您可以执行的操作是:

  1. 清空水壶
  2. 装满一壶
  3. 将水从一个罐子倒入另一个罐子,直到其中一个罐子是空的或满的。

有几种方法可以解决这个问题,包括 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 升水壶)

  1. 将 m 升罐装满,然后倒入 n 升罐中。
  2. 每当 m 升水壶变空时,将其装满。
  3. 每当 n 升水罐装满时,它就会倒空。
  4. 重复步骤 1、2、3,直到 n 升水壶或 m 升水壶装有 d 升水。

步骤 1、2 和 3 中的每一步都算作我们执行的一个操作。假设算法 1 在 C1 次操作中完成了任务。

解决方案 2(总是从 n 升水壶倒入 m 升水壶)

  1. 将 n 升水壶装满,然后倒入 m 升水壶。
  2. 每当 n 升水壶变空时,将其装满。
  3. 每当 m 升水罐装满时,它就会倒空。
  4. 重复步骤 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 现场工作专业课程学生竞争性编程现场课程