分别有两个容量为“ 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升。