📜  使用两个容器和无限供水量到一公升

📅  最后修改于: 2021-04-29 15:34:36             🧑  作者: Mango

分别有两个容量为“ a”和“ b”的容器。我们有无限的供水。给出一种有效的算法,以在其中一个容器中精确地制造1升水。您可以在任何时间点将任何船只上的水全部倒掉。假设“ a”和“ b”是互质数。

步骤如下:
设V1为容量’a’的容器,而V2为容量’b’的容器,且’a’小于’b’。
1)在V1中的水量不为1时执行以下操作。
…。 a)如果V1为空,则完全填充V1
…。 b)将水从V1转移到V2。如果V2变满,则将剩余的水留在V1中并清空V2
2)在步骤1中终止循环后,V1将有1升。

以下是上述算法的C++实现。

C++
/* Sample run of the Algo for V1 with capacity 3 and V2 with capacity 7
1. Fill V1:                               V1 = 3, V2 = 0
2. Transfer from V1 to V2, and fill V1:   V1 = 3, V2 = 3
2. Transfer from V1 to V2, and fill V1:   V1 = 3, V2 = 6
3. Transfer from V1 to V2, and empty V2:  V1 = 2, V2 = 0
4. Transfer from V1 to V2, and fill V1:   V1 = 3, V2 = 2
5. Transfer from V1 to V2, and fill V1:   V1 = 3, V2 = 5
6. Transfer from V1 to V2, and empty V2:  V1 = 1, V2 = 0
7. Stop as V1 now contains 1 litre.
  
Note that V2 was made empty in steps 3 and 6 because it became full */
  
#include 
using namespace std;
  
// A utility function to get GCD of two numbers
int gcd(int a, int b) { return b? gcd(b, a % b) : a; }
  
// Class to represent a Vessel
class Vessel
{
    // A vessel has capacity, and current amount of water in it
    int capacity, current;
public:
    // Constructor: initializes capacity as given, and current as 0
    Vessel(int capacity) { this->capacity = capacity; current = 0; }
  
    // The main function to fill one litre in this vessel. Capacity of V2
    // must be greater than this vessel and two capacities must be co-prime
    void makeOneLitre(Vessel &V2);
  
    // Fills vessel with given amount and returns the amount of water 
    // transferred to it. If the vessel becomes full, then the vessel 
    // is made empty.
    int transfer(int amount);
};
  
// The main function to fill one litre in this vessel. Capacity 
// of V2 must be greater than this vessel and two capacities 
// must be coprime
void Vessel:: makeOneLitre(Vessel &V2)
{
    // solution exists iff a and b are co-prime
    if (gcd(capacity, V2.capacity) != 1)
        return;
  
    while (current != 1)
    {
        // fill A (smaller vessel)
        if (current == 0)
            current = capacity;
  
        cout << "Vessel 1: " << current << "   Vessel 2: " 
             << V2.current << endl;
  
        // Transfer water from V1 to V2 and reduce current of V1 by
        //  the amount equal to transferred water
        current = current - V2.transfer(current);
    }
  
    // Finally, there will be 1 litre in vessel 1
    cout << "Vessel 1: " << current << "   Vessel 2: " 
         << V2.current << endl;
}
  
// Fills vessel with given amount and returns the amount of water 
// transferred to it. If the vessel becomes full, then the vessel 
// is made empty
int Vessel::transfer(int amount)
{
    // If the vessel can accommodate the given amount
    if (current + amount < capacity)
    {
        current += amount;
        return amount;
    }
  
    // If the vessel cannot accommodate the given amount, then
    // store the amount of water transferred
    int transferred = capacity - current;
  
    // Since the vessel becomes full, make the vessel
    // empty so that it can be filled again
    current = 0;
  
    return transferred;
}
  
// Driver program to test above function
int main()
{
    int a = 3, b = 7;  // a must be smaller than b
  
    // Create two vessels of capacities a and b
    Vessel V1(a), V2(b);
  
    // Get 1 litre in first vessel
    V1.makeOneLitre(V2);
  
    return 0;
}


Java
/* Sample run of the Algo for V1 with capacity 3 and V2 with capacity 7
1. Fill V1:                             V1 = 3, V2 = 0
2. Transfer from V1 to V2, and fill V1: V1 = 3, V2 = 3
2. Transfer from V1 to V2, and fill V1: V1 = 3, V2 = 6
3. Transfer from V1 to V2, and empty V2: V1 = 2, V2 = 0
4. Transfer from V1 to V2, and fill V1: V1 = 3, V2 = 2
5. Transfer from V1 to V2, and fill V1: V1 = 3, V2 = 5
6. Transfer from V1 to V2, and empty V2: V1 = 1, V2 = 0
7. Stop as V1 now contains 1 litre.
  
Note that V2 was made empty in steps 3 and 6 because it became full */
  
class GFG
{
  
    // A utility function to get GCD of two numbers
    static int gcd(int a, int b) 
    {
        return b > 0 ? gcd(b, a % b) : a;
    }
  
    // Class to represent a Vessel
    static class Vessel 
    {
          
        // A vessel has capacity, and 
        // current amount of water in it
        int capacity, current;
  
        // Constructor: initializes capacity
        // as given, and current as 0
        public Vessel(int capacity)
        {
            this.capacity = capacity;
            current = 0;
        }
  
        // The main function to fill one litre 
        // in this vessel. Capacity of V2 must be
        // greater than this vessel and two capacities
        // must be coprime
        void makeOneLitre(Vessel V2)
        {
            // solution exists iff a and b are co-prime
            if (gcd(capacity, V2.capacity) != 1)
                return;
  
            while (current != 1)
            {
                // fill A (smaller vessel)
                if (current == 0)
                    current = capacity;
  
                System.out.print("Vessel 1: " + current + 
                            " Vessel 2: " + V2.current + "\n");
  
                // Transfer water from V1 to V2 and 
                // reduce current of V1 by
                // the amount equal to transferred water
                current = current - V2.transfer(current);
            }
  
            // Finally, there will be 1 litre in vessel 1
            System.out.print("Vessel 1: " + current + 
                        " Vessel 2: " + V2.current + "\n");
        }
  
        // Fills vessel with given amount and 
        // returns the amount of water
        // transferred to it. If the vessel 
        // becomes full, then the vessel
        // is made empty
        int transfer(int amount)
        {
            // If the vessel can accommodate the given amount
            if (current + amount < capacity) 
            {
                current += amount;
                return amount;
            }
  
            // If the vessel cannot accommodate
            // the given amount, then store
            // the amount of water transferred
            int transferred = capacity - current;
  
            // Since the vessel becomes full, make the vessel
            // empty so that it can be filled again
            current = 0;
  
            return transferred;
        }
    }
  
    // Driver program to test above function
    public static void main(String[] args)
    {
        int a = 3, b = 7; // a must be smaller than b
  
        // Create two vessels of capacities a and b
        Vessel V1 = new Vessel(a);
        Vessel V2 = new Vessel(b);
  
        // Get 1 litre in first vessel
        V1.makeOneLitre(V2);
    }
}
  
// This code is contributed by 29AjayKumar


C#
/* Sample run of the Algo for V1 with capacity 3 and V2 with capacity 7
1. Fill V1:                             V1 = 3, V2 = 0
2. Transfer from V1 to V2, and fill V1: V1 = 3, V2 = 3
2. Transfer from V1 to V2, and fill V1: V1 = 3, V2 = 6
3. Transfer from V1 to V2, and empty V2: V1 = 2, V2 = 0
4. Transfer from V1 to V2, and fill V1: V1 = 3, V2 = 2
5. Transfer from V1 to V2, and fill V1: V1 = 3, V2 = 5
6. Transfer from V1 to V2, and empty V2: V1 = 1, V2 = 0
7. Stop as V1 now contains 1 litre.
  
Note that V2 was made empty in steps 3 and 6 because it became full */
  
using System;
  
class GFG
{
  
    // A utility function to get GCD of two numbers
    static int gcd(int a, int b) 
    {
        return b > 0 ? gcd(b, a % b) : a;
    }
  
    // Class to represent a Vessel
    class Vessel 
    {
          
        // A vessel has capacity, and 
        // current amount of water in it
        int capacity, current;
  
        // Constructor: initializes capacity
        // as given, and current as 0
        public Vessel(int capacity)
        {
            this.capacity = capacity;
            current = 0;
        }
  
        // The main function to fill one litre 
        // in this vessel. Capacity of V2 must be
        // greater than this vessel and two capacities
        // must be coprime
        public void makeOneLitre(Vessel V2)
        {
            // solution exists iff a and b are co-prime
            if (gcd(capacity, V2.capacity) != 1)
                return;
  
            while (current != 1)
            {
                // fill A (smaller vessel)
                if (current == 0)
                    current = capacity;
  
                Console.Write("Vessel 1: " + current + 
                            " Vessel 2: " + V2.current + "\n");
  
                // Transfer water from V1 to V2 and 
                // reduce current of V1 by
                // the amount equal to transferred water
                current = current - V2.transfer(current);
            }
  
            // Finally, there will be 1 litre in vessel 1
            Console.Write("Vessel 1: " + current + 
                        " Vessel 2: " + V2.current + "\n");
        }
  
        // Fills vessel with given amount and 
        // returns the amount of water
        // transferred to it. If the vessel 
        // becomes full, then the vessel
        // is made empty
        int transfer(int amount)
        {
            // If the vessel can accommodate the given amount
            if (current + amount < capacity) 
            {
                current += amount;
                return amount;
            }
  
            // If the vessel cannot accommodate
            // the given amount, then store
            // the amount of water transferred
            int transferred = capacity - current;
  
            // Since the vessel becomes full, make the vessel
            // empty so that it can be filled again
            current = 0;
  
            return transferred;
        }
    }
  
    // Driver program to test above function
    public static void Main(String[] args)
    {
        int a = 3, b = 7; // a must be smaller than b
  
        // Create two vessels of capacities a and b
        Vessel V1 = new Vessel(a);
        Vessel V2 = new Vessel(b);
  
        // Get 1 litre in first vessel
        V1.makeOneLitre(V2);
    }
}
  
// This code is contributed by Rajput-Ji


输出:

Vessel 1: 3   Vessel 2: 0
Vessel 1: 3   Vessel 2: 3
Vessel 1: 3   Vessel 2: 6
Vessel 1: 2   Vessel 2: 0
Vessel 1: 3   Vessel 2: 2
Vessel 1: 3   Vessel 2: 5
Vessel 1: 1   Vessel 2: 0

这是如何运作的?

为了证明该算法有效,我们需要证明在while循环中经过一定次数的迭代后,我们将在V1中获得1升的水。
假设“ a”是容器V1的容量,“ b”是容器V2的容量。由于我们反复将水从V1转移到V2直到V2变满,所以当V2第一次变满时,我们在V1中会有“ a – b(mod a)”水。一旦V2变满,便将其清空。当V2第二次充满时,V1中将有“ a – 2b(mod a)”水。我们重复上述步骤,并在容器V2装满并排空“ n”次后,在V1中得到“ a – nb(mod a)”水。我们需要证明,对于有限整数“ n”,“ a – nb(mod a)”的值将为1。为了证明这一点,让我们考虑以下互质数的性质。
对于任何两个互质整数’a’和’b’,整数’b’具有一个乘积逆模’a’。换句话说,存在一个整数“ y”,使得“ b * y≡1(mod)a”(请参见此处的第三点)。经过’(a – 1)* y’迭代后,我们在V1中会有’a – [(a-1)* y * b(mod a)]’水,该表达式的值为’a – [(a – 1)* 1] mod a’等于1。因此算法收敛,我们在V1中得到1升。