倒水问题(算法挑战)

来源:互联网 发布:linux用yum命令下载 编辑:程序博客网 时间:2024/06/01 08:35

我想我们都做过这么一道题:
有两个容器,容积分别为A升和B升,有无限多的水,现在需要C升水。
我们还有一个足够大的水缸,足够容纳C升水。起初它是空的,我们只能往水缸里倒入水,而不能倒出。
可以进行的操作是:
把一个容器灌满;
把一个容器清空(容器里剩余的水全部倒掉,或者倒入水缸);
用一个容器的水倒入另外一个容器,直到倒出水的容器空或者倒入水的容器满。
问是否能够通过有限次操作,使得水缸最后恰好有C升水。
输入:三个整数A, B, C,其中 0 < A , B, C <= 1000000000
输出:true或false,表示能否达到要求。

例如:
5升水、4升水的杯子、倒出3升水。做法有很多。其中一个 4-(5-4);解释:将4升杯装满导入空的5升杯中。再将4升杯装满倒置入5升杯中、使之装满!此时4升杯中剩余3升!


问题补充:


判断出可以得到C升水之后、要求列出操作次数最少的一组方法?

thanks丶墨
编辑于2013-09-03
该问题被发起关闭投票

投票剩余时间:参与关闭投票 (/3)

该问题被发起重新开启投票

投票剩余时间:参与重新开启投票 (/3)

之前被关闭原因:
该问题被发起删除投票

投票剩余时间:参与删除投票 (/3)

发起了声誉值为分的悬赏
距离悬赏到期还有:
该问题已经在很久很久以前被关闭

参与关闭投票者:

关闭原因:

该问题如果有必要重新开启? 请发起开启投票
该问题已经被锁定

锁定原因:()

该问题已被保护

保护原因:避免来自新用户不合宜或无意义的致谢、跟帖答案。

该问题已成功删除,仅对您可见,其他人不能够查看。取消删除问题
评论 (0) •分享 • 链接 • 2013-09-02 
7个答案
票 数
  • 票 数
  • 最 新
  • 活 跃

您的投票让 灵剑2012 声誉值增加了10分。

支持投票,不仅能让回答用户获得声誉值,让好答案排序靠前,更能帮助社区筛选出好的内容,构建高质量的知识库。

  • 灵剑2012

    2 票

  • 灵剑2012
    6194

倒水的过程有以下几种:设容器中剩余水量为x,A>B,则将水倒入B直至B满:x=>x-B;从B倒入满满一容器的水:x=>x+B;将A倒满水然后倒入B直至B满:x=>A-(B-x)即x=>x+A-B;将B倒满水然后倒入A直至A满:x=>B-(A-x)即x=>x-(A-B)。因此能倒出的水的容量一定能写成X = mA + nB,因此X应当是gcd(A,B)的倍数。
反过来,如果X是gcd(A,B)的倍数,则一定存在m,n使得mA + n(A-B) = X,当X<lcd(A,B)时m和n是唯一的。根据m和n的值可以推算出倒水的方案。

该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (3) • 链接 • 2013-09-05
  • 0 支持
    谢灵哥,意思大致明白!代码还是写不出来!糗了! – thanks丶墨2013-09-05
  • 0 支持
    @thanks丶墨 计算出对应的m和n的过程是一个经典的辗转相除算法,通常叫做扩展的欧几里得辗转相除,可以查一下数论的相关内容。倒水的方案的要点在于倒的过程必须保证0<=x<=A,因此需要把C拆成m*A+n*B+x,x符合0<=x<=A,是最后一次要调整的水量。要求出最少步骤还是有一些难度的。 – 灵剑20122013-09-05
  • 0 支持
    @灵剑2012 嗯。欧几里得辗转相除我了解。我也觉得求出最少步骤很困难! – thanks丶墨2013-09-05

您的投票让 thanks丶墨 声誉值增加了10分。

支持投票,不仅能让回答用户获得声誉值,让好答案排序靠前,更能帮助社区筛选出好的内容,构建高质量的知识库。

  • thanks丶墨

    0 票

  • thanks丶墨
    274

对于上面的题目研究结果如下:
得出能否实现似乎很简单、但是如果可以实现,那么去得到最快的实现方法却很难!

  
  1. public static boolean can( int a , int b , int c ) { 
  2.     int temp = gcd( a , b ); 
  3.     //规则:如果可以得到c ,那么必然满足 c为 temp的倍数 
  4.     return c%temp == 0; 
  5. } 
  6. // 得到两个数的最大公约数 
  7. public static int gcd( int a , int b ) { 
  8.     return ( b > 0 ) ? gcd( b , a % b ) : a; 
  9. }
该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (0) • 链接 • 2013-09-02

您的投票让 假行僧 声誉值增加了10分。

支持投票,不仅能让回答用户获得声誉值,让好答案排序靠前,更能帮助社区筛选出好的内容,构建高质量的知识库。

  • 假行僧

    0 票

  • 假行僧
    1

广度优先算法~
用一个递归, 在每一层, 搜索所有的可能性, 在一个链表中记录.
搜索完这层之后, 链表指针向后移一位, 继续递归.

返回条件:
1.当前状态是目标状态.
2.搜索完所有的状态, 已经没有其他的可能了.(每次增加链表的时候, 都做一次"当前状态是否重复"的判断, 用 字符串 或者 数组 都可以.)

最优解:
链表反着打印就可以了~

该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (1) • 链接 • 2013-09-04
  • 0 支持
    so 我还得先研究下这个算法机制! 谢过! – thanks丶墨2013-09-04

您的投票让 lxgwm2008 声誉值增加了10分。

支持投票,不仅能让回答用户获得声誉值,让好答案排序靠前,更能帮助社区筛选出好的内容,构建高质量的知识库。

  • lxgwm2008

    0 票

  • lxgwm2008
    1

中国剩余定理的问题!可以了解一下数论!
条件是只要两个容器的容积互质,那么肯定有解,且只有一个解!

该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (0) • 链接 • 2013-09-04

您的投票让 chen_an_2005 声誉值增加了10分。

支持投票,不仅能让回答用户获得声誉值,让好答案排序靠前,更能帮助社区筛选出好的内容,构建高质量的知识库。

  • chen_an_2005

    0 票

  • chen_an_2005
    1

A,B的最大公约数能够整除C,就一定有解。反之无解。
实际程序执行没必要求最大公约数,只要A、B之差能整除C就有解了。

  
  1. bool can_fill(int a, int b, int c) 
  2. { 
  3.   if (a==0 || b==0) return false; 
  4.   if (c%a==0 || c%b==0) return true; 
  5.   if (a>b)  
  6.     return can_fill(a-b, b, c); 
  7.   else  
  8.     return can_fill(a, b-a, c); 
  9. }
该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (0) • 链接 • 2013-09-04

您的投票让 奇幻空间 声誉值增加了10分。

支持投票,不仅能让回答用户获得声誉值,让好答案排序靠前,更能帮助社区筛选出好的内容,构建高质量的知识库。

  • 奇幻空间

    0 票

  • 奇幻空间
    1

设要求为m升:
1.求最小m(m_min):
n(A+B)>m>=(n-1)(A+B)
m_min=n(A+B)-m==0?true:false
2.求此时最大m(m_max):
m_max=|n(A-B)|==0?true:
xA+yB=m_max
若存在整数(x,y)---〉true
else: false

该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (0) • 链接 • 2013-09-05

您的投票让 箫筱沐羽 声誉值增加了10分。

支持投票,不仅能让回答用户获得声誉值,让好答案排序靠前,更能帮助社区筛选出好的内容,构建高质量的知识库。

  • 箫筱沐羽

    0 票

  • 箫筱沐羽
    1

其实可以扩展到n个桶要倒出w升水的问题
同样要实现这目标,w必须是这n个桶容量最大公约数的倍数。
设n个桶的容量为a1,a2,...,an,最大公约数为c,
即(a1,a2,...,an)= c
=>u1a1+u2a2+...+unan=c, =>w/c(u1a1+u2a2+...+unan)=w //同时乘以w/c
所以要实现这一目标w/c必须是整数,即w是c的倍数。
注意Ui可能为负数,可能不唯一,也就代表倒水的顺序不唯一。

该答案已被锁定,无法对其进行评论,编辑及投票。
()
评论 (0) • 链接 • 2013-09-10