倒水问题-经典面试题



最常见的是给你一个容量为5升的杯子和一个容量为3升的杯子,水不限使用,要求精确得到4升水.
2) 编程实现
DFS(深度优先)搜索,每次我们有6种选择,只要不断的尝试下去,总可以搜索完所有的状态,找到一个解。也可以用宽度优先搜索(BFS)
05public class PourWater {
06    //所有的6中操作。
07    static String operations[] = {" 装满 x "" 装满 y "," 清空X "" 清空Y "" x -> y "" y -> x "};
08    static Stack<Integer> stack = new Stack<Integer>();
09    static int L1,L2 ;//两个杯子的容量
10    static int target; //目标容量
11    static int len;
12    //防止重复搜索
13    static boolean dp[][] ;
14    public static void dfs(int x,int y){
15        if(dp[x][y]) return;
16        dp[x][y] = true;
17        //找到解决方案
18        if(x == target || y == target){
19            System.out.println("dfs方法 一个倒水方案:");
20            for(int oper:stack)
21                System.out.println(operations[oper]);
22            return;
23        }
24        stack.push(0);
25        dfs(L1,y);
26        stack.pop();
27
28        stack.push(1);
29        dfs(x,L2);
30        stack.pop();
31
32        stack.push(2);
33        dfs(0,y);
34        stack.pop();
35
36        stack.push(3);
37        dfs(x,0);
38        stack.pop();
39
40        //x向y倒水
41        stack.push(4);
42        if(x >= (L2-y) )  //x倒不完,还有剩余
43            dfs(x - (L2-y),L2);
44        else
45            dfs(0 ,y + x); //x没有剩余
46        stack.pop();
47
48        //y向x倒水,需要判断能否倒完
49        stack.push(5);
50        if(y >= (L1-x))
51            dfs(L1,y - (L1-x));
52        else
53            dfs(0,y + x);
54        stack.pop();
55    }
X. http://blog.csdn.net/morewindows/article/details/7481851
可以用宽度优先搜索(BFS),也可以用穷举法。穷举法实现比较方便,其基本思想是用:用小桶容量的倍数对大桶的容量进行取余
又在网上找到一个穷举法,利用了扩展欧几里得算法(同余定理)的一些概念。
穷举法实现比较方便,其基本思想是用:用小桶容量的倍数对大桶的容量进行取余。比如3升的桶和5升的桶得到4升水可以这样做:
3 % 5 = 3
6 % 5 = 1
9 % 5 = 4
成功得到4升水。(PS:上面的过程用如何用文字描述了?)
将倒水问题的基本思想用易于编程的话来翻译下——不断用小桶装水倒入大桶,大桶满了立即清空,每次判断下二个桶中水的容量是否等于指定容量
同样,用7升的桶和11升的桶得到2升水可以这样做:
7 % 11 = 7
14 % 11 = 3
21 % 11 = 10
28 % 11 = 6
35 % 11 = 2
成功得到2升水。
const string OPERATOR_NAME[7] = {
10    "装满A桶","装满B桶",
11    "将A桶清空","将B桶清空",
12    "A桶中水倒入B桶","B桶中水倒入A桶",
13    "成功"
14};
15int main()
16{
17    cout<<"热门智力题 - 打水问题"<<endl;
18    cout<<"  --by MoreWindows( http://blog.csdn.net/MoreWindows )--\n"<<endl;
19
20    int    a_volume, b_volume, goal_volume;
21    vector<string> record;       //记录操作步数
22    int    ai;
23    int    i, a_water, b_water;
24
25    cout<<"请输入A桶容量,B桶容量,目标容量:";
26    cin>>a_volume>>b_volume>>goal_volume;
27    a_water = b_water = 0; //A桶,B桶中有多少升水
28    char szTemp[30];
29    while (true)
30    {
31        if (a_water == 0)//A桶没水,就装满水
32        {
33            a_water = a_volume;
34            sprintf(szTemp, "         A:%d  B:%d", a_water, b_water);
35            record.push_back(OPERATOR_NAME[0] + szTemp);//fill A
36        }
37        else
38        {
39            //如果A桶的水比(B桶容量-B桶的水)要多
40            if (a_water > b_volume - b_water)
41            {
42                //A桶的水==A桶的水+B桶的水-B桶容量
43                a_water = a_water + b_water- b_volume;
44                b_water = b_volume;      //B桶的水装满了
45                sprintf(szTemp, "  A:%d  B:%d", a_water, b_water);
46                record.push_back(OPERATOR_NAME[4] + szTemp);//A->B  
47                if (a_water == goal_volume)
48                    break;
49                b_water = 0;            //将B桶清空
50                sprintf(szTemp, "       A:%d  B:%d", a_water, b_water);
51                record.push_back(OPERATOR_NAME[3] + szTemp);
52            }
53            else
54            {
55                //B桶的水==A桶的水+B桶的水
56                b_water += a_water;
57                a_water = 0;
58                sprintf(szTemp, "  A:%d  B:%d", a_water, b_water);
59                record.push_back(OPERATOR_NAME[4] + szTemp);//A->B
60                if (b_water == goal_volume)
61                    break;
62            }
63        }
64    }
65    record.push_back(OPERATOR_NAME[6]); //success
66    cout<<"\n---------------------------------------------------"<<endl;
67    cout<<"一个可行的倒水方案如下"<<endl;
68    vector<string>::iterator pos;
69    for (pos = record.begin(); pos != record.end(); pos++)
70        cout<<*pos<<endl;
71    cout<<"---------------------------------------------------"<<endl;
72    return 0;
73}

http://5261.github.io/Pour-water/
考虑三个容器内水量分别为

v0v1v2的状态(v0,v1,v2),我们可以通过枚举所有可能的倒水操作,扩展出该状态的后继,于是该题又化归为图上最短路的问题,因为总水量是一定的(将水缸的容量和初始设为一个足够大的数),并且都是整数,当v0,v1确定的时候,v2也是确定的,也就是说我们可以仅通过v0,v1的值来确定一个状态,所以我们可以开一个二维数组来判重,这还是可以承受的。
如果是要求倒水步数最少,即为无权图最短路以BFS解决,如果要求倒水量最少,也可以加权搜索,即把一般队列换成优先队列,每次扩展倒水量最少的节点,同样可以解决,本题属于第一种情况。
#define STATE_SIZE 3*sizeof(int)
#define MAXCAP 126

struct Node{
    int volume[3];
    int dist;

    Node(int a, int b, int c){
        volume[0] = a, volume[1] = b, volume[2] = c;
        dist = 0;
    }

    Node(Node *father){
        memcpy(volume, father->volume, STATE_SIZE);
        dist = father->dist + 1;
    }
};

int cap[3];
int target;
bool visted[MAXCAP][MAXCAP];

inline int BFS(){
    std::queue<Node*> Q;
    Node *s = new Node(0, 0, 2 * MAXCAP);

    Q.push(s);
    s->dist = 0;
    visted[0][0] = true;
    while(!Q.empty()){
        Node *v = Q.front(); Q.pop();
        if(v->volume[0] == target || v->volume[1] == target) return v->dist;
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++) if(i != j){
                // 枚举可能的倒水方案,从i倒水到j
                if(v->volume[i] == 0 || v->volume[j] == cap[j]) continue;
                //i中无水或j中已满,均不合法
                int amount = std::min(cap[j], v->volume[i] + v->volume[j]) - v->volume[j];
                // 细节: 确定倒水量
                Node *vi = new Node(v);
                int &a = vi->volume[i], &b = vi->volume[j];
                //技巧: 为比较长的变量名声明引用可以让代码更简洁清晰
                a -= amount;
                b += amount;
                if(!visted[a][b]){
                    visted[a][b] = true;
                    Q.push(vi);
                }
            }
        }
    }

    return -1;
}


http://www.cnblogs.com/hiddenfox/p/3395950.html

1 public static boolean can(int a,int b,int c) {
 2     int r;
 3     while (true) {
 4         r = a % b;
 5         if (r != 0) {
 6             a = b;
 7             b = r;
 8         } else {
 9             break;
10         }
11     } 
12     return c%b == 0;    //b现在是最大公约数,若c能被b整除,则可以
13 }
一般性问题

有两个容器,容积分别为A升和B升,有无限多的水,现在需要C升水。 我们还有一个足够大的水缸,足够容纳C升水。起初它是空的,我们只能往水缸里倒入水,而不能倒出。 可以进行的操作是: 把一个容器灌满; 把一个容器清空(容器里剩余的水全部倒掉,或者倒入水缸); 用一个容器的水倒入另外一个容器,直到倒出水的容器空或者倒入水的容器满。     问是否能够通过有限次操作,使得水缸最后恰好有C升水。
上面的穷举法已经给出了一些结论:我们可以有这样一个公式:xA + yB = C ;只要x,y有整数解,这个问题就是可解的。其中x,y 可以为负整数。 例如对于 A=3, B=5,  C=4,其实就是  3*A – 1*B = 4;  即向A中倒满了3次,B清空一次。
http://www.cnblogs.com/bestDavid/p/Dropwarter.html
对题目做简要的处理分析后,C升水是可以分多次倒入的,假设A > B,那么每次可以倒的水的量为A , B , (A + B) ,( A - B)升水,设置4个因子,分别为x1 , x2, x3, x4 , (x1 , x2, x3, x4 属于整数),如果可以使得水缸最后恰好有C升水,那么必然存在整数x1 , x2, x3, x4,使得

Ax1 + Bx2 + (A + B)x3 + (A - B)x4 = C 等式成立;
对等式做一定的变换,得到公式
(x1 + x3 + x4)A + (x2 + x3 - x4)B = C ; --( 1-1 )
  设 x = x1 + x3 + x4 , y = x2 + x3 - x4 , x, y 均为整数;最终得到公式
xA + yB = C ; --( 1-2 )
x1 , x2, x3, x4 可以假设为正整数,用几个for循环可以实现,但是时间复杂度太


扩展的欧几里德算法,算法描述:
定理:
  对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by.
  根据欧几里德扩展算法,Gcd(A, B) = Ax + By,求出A和B的最大公约数,如果C能被最大公约数整除Gcd(A, B) 整除,那就可以实现水缸里恰好为C升水;

根据欧几里德扩展算法,gcd(A, B) = Ax + By,求出A和B的最大公约数,如果C能被最大公约数整除Gcd(A, B) 整除,那就可以实现水缸里恰好为C升水;
那题目就直接转换为求A 、B的最大公约数了
int gcd(int a, int b)
05{
06    int m = a, n = b , r = 1;
07    while(1)
08    {
09        r = m % n;
10        if(r == 0)
11        {
12            return n;
13        }
14        else
15        {
16            m = n;
17            n = r;
18        }
19    }
20}
21//返回值1表示能使得水缸恰好有C升水,0表示不能
22int can(int a,int b,int c)
23{
24    int result = 0;
25    result = gcd(a,b);
26    if(c % result == 0 )
27    {
28        return 1;
29    }
30    else
31    {
32        return 0;
33    }
34}
参考:http://www.cnblogs.com/bestDavid/p/Dropwarter.html
https://github.com/aishangzoulu/raylew_algorithm/blob/master/src/main/java/com/raylew/algorithm/book1/%E5%80%92%E6%B0%B4%E9%97%AE%E9%A2%98.java
http://blog.csdn.net/morewindows/article/details/7481851
http://blog.csdn.net/crazy1235/article/details/18964001
有两个容器,容积分别为A升和B升,有无限多的水,现在需要C升水。
我们还有一个足够大的水缸,足够容纳C升水。起初它是空的,我们只能往水缸里倒入水,而不能倒出。
可以进行的操作是:
  1. 把一个容器灌满;
  2. 把一个容器清空(容器里剩余的水全部倒掉,或者倒入水缸);
  3. 用一个容器的水倒入另外一个容器,直到倒出水的容器空或者倒入水的容器满。
    问是否能够通过有限次操作,使得水缸最后恰好有C升水。

输入:三个整数A, B, C,其中 0 < A , B, C <= 1000000000
输出:0或1,表示能否达到要求。
    public static boolean can(int a,int b,int c) {
  int res = mod(a, b);
  if(c%res == 0){
   return true;
  }else{
   return false;
  }
    }
 public static int mod(int a, int b){
  if(a % b == 0){
   return b;
  }else{
   return mod(b, a%b);
  }
 }

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts