zoukankan      html  css  js  c++  java
  • [LintCode 1674.] 倒可乐

    LintCode 1674. 倒可乐

    CAT 专属题目 中等难度题

    替代链接 HDU 1495.

    题目描述

    给定一个容积为 s 的装满可乐的瓶子和两个容积分别为 n 和 m 的空杯子, 其中 n + m = s. 问能否通过在三个容器之间来回倒可乐来平分这 s 体积的可乐? 如果可以, 返回最少倾倒可乐的次数; 反之返回 -1.

    由于瓶子和杯子上没有刻度, 所以当你从一个容器倒可乐到另一个容器中时, 只能一直倒可乐直到一个容器空了或者另一个满了为止.

    样例

    样例 1:

    输入: s = 4, n = 1, m = 3
    输出: 3
    解释:
    首先, 从瓶子倒3体积的可乐到第二个杯子, 瓶子和两个杯子中分别有 1, 0, 3 体积的可乐.
    然后, 倒1体积的可乐从第二个杯子到第一个杯子, 此时三个容器分贝有 1, 1, 2 体积的可乐.
    最后, 倒1体积的可乐从第一个杯子到瓶子, 此时瓶子和第二个杯子中都有 2 体积的可乐, 平分.
    样例 2:

    输入: s = 7, n = 4, m = 3
    输出: -1
    解释: 7 体积的可乐不能被平分.

    注意事项

    s <= 100

    解题思路

    两种思路:

    1. 第一种方法是搜索,使用BFS,三个杯子两两操作,每一步都有6种倾倒方式。这种也能AC,开销大一点。
    2. 第二种是数论。找出其中的数学规律,加以解决。

    我们注意到,s = m + n,从而可以得出结论 gcd(m, n) == gcd(s, m, n)

    如果m == n,只需要倒一次就可以了。
    如果m != n不妨假设m > n,那么最后平分水的时候,一半在s中,一半在m中,因为n的体积不到瓶子的一半。
    s、m、n 之间的倒水,其实就是辗转相减,最后能减出的最小单位是 gcd(m, n)

    设 m 和 n 各自净倒水的次数分别为 x 和 y,即各自倒出水次数减去倒入水次数之差为 x 和 y,则两个杯子倒水次数之和最少为 s / gcd(m,n)
    下面的推导使用 a 和 b 表示的 m 和 n:

    由于x 和 y 不可能同正同负,必然一个正一个负。

    所有的操作其实都是 s->m m->n n->s 这三个操作的排列组合而已。
    例如:

    1. (s,m,n)=(4,3,1) 的倒水方案是: s->m, m->n, n->s
    2. (s,m,m)=(6,5,1) 的倒水方案是: s->m, m->n, n->s, m->n, n->s
    3. (s,m,n)=(8,5,3) 的倒水方案是: s->m, m->n, n->s, m->n, s->m, m->n, n->s

    可以看到,每一次两个杯子之间的操作,都伴随着一次大瓶子的辅助使用。
    我们把倒水操作两两一组划分,可以看到每个组要么是 m/n 的净倒出组,要么是 m/n 的净倒入组,没有任何一组是只有m和n都倒出倒入相等次数的。
    并且最后一组只有半个,所以总步数是 (c + d) / 2 * 2 - 1 = s / gcd(m, n) - 1

    参考代码

    class Solution {
    public:
        /**
         * @param s: the volume of cola
         * @param n: the volume of the first cup
         * @param m: the volume of the second cup
         * @return: the minimum number of times to be inverted
         */
        int getMinTimes(int s, int n, int m) {
            // Write your code here
            s /= __gcd(n,m);
            if (s % 2 == 0) return s-1;
            return -1;
        }
    };
    

    参考文献:

    https://www.cnblogs.com/ECJTUACM-873284962/p/6750320.html

  • 相关阅读:
    多线程(10) — Future模式
    Java的设计模式(7)— 生产者-消费者模式
    多线程(9) — 无锁
    多线程(8) — ThreadLocal
    Java的设计模式(6)— 模板模式
    多线程(7)— JDK对锁优化的努力
    多线程(6) — 提高锁性能的一些看法
    复位电路 解析
    C语言数据类型
    MSP下载方式
  • 原文地址:https://www.cnblogs.com/zhcpku/p/14264184.html
Copyright © 2011-2022 走看看