Отмерьте один литр, используя две емкости и бесконечную подачу воды.
Имеются два сосуда вместимостью «а» и «б» соответственно. У нас безграничное водоснабжение. Приведите эффективный алгоритм, позволяющий сделать ровно 1 литр воды в одной из емкостей. Вы можете вылить всю воду из любого сосуда в любой момент. Предположим, что «a» и «b» взаимно просты.
Ниже приведены шаги:
Пусть V1 - сосуд вместимостью «a», V2 - сосуд вместимостью «b», а «a» меньше, чем «b».
1) Выполните следующие действия, пока количество воды в V1 не равно 1.
…. а) Если V1 пуст, то полностью заполните V1
…. б) Перелейте воду из V1 в V2. Если V2 становится полным, оставьте оставшуюся воду в V1 и слейте V2.
2) V1 будет иметь 1 литр после завершения цикла на шаге 1. Возврат.
Following is C++ implementation of the above algorithm.
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 <iostream> 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 + "
" ); // 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 + "
" ); } // 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 + "
" ); // 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 + "
" ); } // 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 |
Выход:
Судно 1: 3 Судно 2: 0 Сосуд 1: 3 Сосуд 2: 3 Сосуд 1: 3 Сосуд 2: 6 Судно 1: 2 Судно 2: 0 Сосуд 1: 3 Сосуд 2: 2 Сосуд 1: 3 Сосуд 2: 5 Судно 1: 1 Судно 2: 0
Как это работает?
Чтобы доказать, что алгоритм работает, нам нужно доказать, что после определенного количества итераций в цикле while мы получим 1 литр в V1.
Пусть «a» - вместимость сосуда V1, а «b» - вместимость V2. Поскольку мы неоднократно переносим воду из V1 в V2 до тех пор, пока V2 не заполнится, у нас будет вода «a - b (mod a)» в V1, когда V2 станет полным в первый раз. Как только V2 наполняется, он опорожняется. У нас будет вода «a - 2b (mod a)» в V1, когда V2 заполнится второй раз. Мы повторяем вышеуказанные шаги и получаем воду «a - nb (mod a)» в V1 после того, как сосуд V2 наполняется и опорожняется «n» раз. Нам нужно доказать, что значение «a - nb (mod a)» будет равно 1 для конечного целого числа «n». Чтобы доказать это, рассмотрим следующее свойство взаимно простых чисел.
Для любых двух взаимно простых целых чисел «a» и «b» целое число «b» имеет мультипликативный обратный по модулю «a». Другими словами, существует целое число «y» такое, что «b * y ≡ 1 (mod) a» (см. 3-й пункт здесь). После итераций '(a - 1) * y' у нас будет вода 'a - [(a-1) * y * b (mod a)]] в V1, значение этого выражения будет' a - [(a - 1) * 1] mod a ', который равен 1. Итак, алгоритм сходится, и мы получаем 1 литр в V1.
Эта статья составлена Аашишем Барнвалом. Пожалуйста, напишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по теме, обсужденной выше.
Вниманию читателя! Не прекращайте учиться сейчас. Освойте все важные концепции DSA с помощью самостоятельного курса DSA по приемлемой для студентов цене и будьте готовы к работе в отрасли. Чтобы завершить подготовку от изучения языка к DS Algo и многому другому, см. Полный курс подготовки к собеседованию .
Если вы хотите посещать живые занятия с отраслевыми экспертами, пожалуйста, обращайтесь к Geeks Classes Live и Geeks Classes Live USA.