代码改变世界

灌水问题

2007-10-15 18:37  老博客哈  阅读(1592)  评论(6编辑  收藏  举报

灌水问题的经典形式是这样的:

  “假设有一个池塘,里面有无穷多的水。现有2个空水壶,容积分别为5升和6升。问题是如何只用这2个水壶从池塘里取得3升的水。”

  当然题外是有一些合理的限制的,比如从池塘里灌水的时候,不管壶里是不是已经有水了,壶一定要灌满,不能和另一个壶里的水位比照一下“毛估估”(我们可以假设壶是不透明的,而且形状也不同);同样的,如果要把水从壶里倒进池塘里,一定要都倒光;如果要把水从一个壶里倒进另一个壶里,也要都倒光,除非在倒的过程中另一个壶已经满了;倒水的时候水没有损失(蒸发溢出什么的)等等等等。

      详细的灌水问题的解答及介绍可以参加这篇文章《灌水问题——经典智力题推而广之一》。

下面谈谈我从一些具体题目中对这个“灌水问题”的理解:

1. nit 1255 取水 (tju 2219 a famous math puzzle)
     题目意思很简单,就是用一些水壶去取一定量的水,问可不可能,这个其实就是使用了上篇文章中的"灌水定理",其实说白了就是扩展欧几里德算法。 不难得到,用d1,d2,...,dn容量的壶去取得L容量的水的充要条件如下:
1.  L不得超过d1+d2+...+dn
2.  gcd(d1,d2,...,dn)必须能够整除L
有了这两个条件就可以轻松解决这面的问题了。

2. zju 1005 Jugs

     题目意思就是给定链各个壶的容积A和B,其中保证A,B互质,然后给定一个需要得到的水的容量,且保证有解,要求最终可以在B壶中得到这么多水的方案,任意方案只要合理均可。这个只要不断的往A壶内加水,一旦A里面有水,就把它往B里面倒,一旦B满,则把B倒空,直到B当中的水为所求的量即可。


3. pku 3414 Pots
      与上面1中的题目不一样的是,此题并不仅仅问是否能够取得这么多的水,而是问能够取得这么多水所需要的最少步数,并把这些步骤输出。与上题相比稍微简单的是,此题仅有两个水壶,且题目是spj的,因为可能存在很多种相同步数的方法得到指定容量的水。
      由于受1题的影响,当时我是这样考虑的,要求最少步数嘛,我可以先用扩展欧几里德算法算出A*x+B*y=C的一组解x0和y0,由0<C<=max(A, B),我们知道如果方程有解,必定x,y中有且仅有一个是正数,不妨设x>0。然后我x=x0-B*t, y = y0+A*t 循环求绝对值之和最小的一组解x', y'。然后只要保证x‘(x'>0)对应的系数的壶装满那么多次,y'(y'<=0)对应系数的壶倒空那么多次就解决了。 但是不难通过一些小的例子来推翻上述的思想,其实这里面的关系还有点小复杂。
   再后来,经nic提醒,才发现,不管我怎么求x,y,怎么装满,倒空... 无非在做一件事情,就是选择某个杯子 为“主杯”,一个作为“辅杯”。总是让“主杯”尽量的装满,然后往“辅杯”尽量的到,然后“辅杯”一满即到,知道出现指定的容量停止,统计总的次数,选取小的那种情况,然后模拟即可。