今天开始定期记录本人在leetcode上刷题时遇到的有意思的题目。
 

517. Super Washing Machines
 
You have n super washing machines on a line. Initially, each washing machine has some dresses or is empty.
For each move, you could choose any m (1 ≤ m ≤ n) washing machines, and pass one dress of each washing machine to one of its adjacent washing machines at the same time .
Given an integer array representing the number of dresses in each washing machine from left to right on the line, you should find the minimum number of moves to make all the washing machines have the same number of dresses. If it is not possible to do it, return -1.

乍看此题,我们可能会想到是否能用DP求解,毕竟像求最值这类问题,是很容易与DP联系在一起的。事实也正是如此。
第一步,我们判断所有的machines能不能被成功地分配到m个相同的组。这很容易判断,在此不赘述。这步做完,我们可以得到每堆machine的最终数量(假如能被成功分配为m个相同的组),记为n。
接下来,我们看一下如何将这个问题分解为子问题,从而易于用DP求解。我们从数组的第一个元素开始看。
第一种情况,该元素=n。这表明第一堆已经不需要再做任何移动。我们仅需求出对剩余的数组(从第二个开始到末尾)的解,该子数组的解就是我们整个问题的解。
第二种情况,该元素>n。这种情况说明,我们需要从第一堆中取出足够的machine,将它移动到相邻的第二堆,将移动的数量记为n1. 然后,再对剩余的子数组递归求解,假设得到的解为n2.这时我们观察题干,不同堆中的移动是独立的。比如堆1移动1个machine到堆2,堆2移动1一个machine到堆3。。。这个移动序列只被记为一次。有这个结论,我们回到第二种情况,n1和n2也是独立的。所以这种情况下我们的解是max(n1,n2)。
第三种情况,该元素<n。这种情况,我们需要从第二堆中取出足够的machine,将它移动到第一堆。如果第二堆的数量仍然不够呢?那就从第三堆取,以此类推。我们可以用一个例子来说明。
 
0,1,3,14,2
 
这个例子最终每堆的数量应该是4.然而第一堆=0,那么我们需要从第二堆中取4个machine(n1),然而第二堆的数量是1,还是不够。且第二堆自己最终数量也必须是4,那么它总共需要从第三堆取7个(n2)。以此类推,第三堆需要从第四堆取8个(n3),才能满足左边所有堆的需求。到第四堆,我们发现,它的数量足够了,不必再向它的右边再取machine了。于是我们可以通过一个循环计算出所需要移动的数量nx = max(n1,n2...)。然后再递归求解剩余子数组形成的子问题,解记为ny。对于本例来说,这个子问题就是对数组第四个元素开始的子数组求出的解。看到这里,也许我们的解可以呼之欲出了,就是max(nx,ny)?
然而,事实并非如此。再次阅读题干,不同的堆上的操作,确实是独立的。但是对同一堆,情况并非如此。还是观察之前的例子,第四堆需要移动8个元素到第三堆,它还需要移动2个元素到右边的第五堆。所以整个问题的解是8+2=10堆,而不是max(8,2)的8堆,原因就在于对同一堆上的操作,没有独立性。所以我们在设计递归函数的时候,除了返回整个操作的最小move数,还必须返回边界元素的move数,从而便于子问题返回时,计算主问题的解。
 
贴上代码:
int findMinMoves(vector<int>& machines) {
if (machines.empty()) return ;
int sum = accumulate(begin(machines), end(machines), );
if (sum % machines.size() == ) {
int target = sum / machines.size();
return findMinMoves(machines, , target).first;
}
else return -;
} // 返回pair<minMove, boundaryMove>
// boundaryMove表示从start位置和start+1位置之间发生move的数量(双向)
pair<int, int> findMinMoves(vector<int>& machines, int start, int target) {
if (start == machines.size() - ) {
return make_pair(, );
}
if (target <= machines[start]) {
int move = machines[start] - target;
machines[start + ] += move;
int minMove = findMinMoves(machines, start + , target).first;
return make_pair(max(move, minMove), move);
}
else {
int i = start;
int maxMove = ;
int move;
do {
move = target - machines[i];
maxMove = max(maxMove, move);
machines[i + ] -= move;
i++;
} while (machines[i] < target);
pair<int, int> rem = findMinMoves(machines, i, target);
int rMove = rem.first;
maxMove = max(maxMove, rMove);
maxMove = max(maxMove, move + rem.second);
return make_pair(maxMove, target - machines[i]);
}
}

Leetcode - 517 Super Washing Machines的更多相关文章

  1. 第十五周 Leetcode 517. Super Washing Machines(HARD) 贪心

    Leetcode517 很有趣的一道题 由于每一步可以任选某些数字对它们进行转移,所以实际上是在求最优解中的最复杂转移数. 那么我们考虑,到底哪一个位置要经过的流量最大呢? 枚举每个位置,考虑它左边的 ...

  2. 517 Super Washing Machines 超级洗衣机

    详见:https://leetcode.com/problems/super-washing-machines/description/ C++: class Solution { public: i ...

  3. 517. Super Washing Machines

    ▶ 超级洗碗机.给定一个有 n 元素的整数数组,我们把 “将指定位置上元素的值减 1,同时其左侧或者右侧相邻元素的值加 1” 称为一次操作,每个回合内,可以选定任意 1 至 n 个位置进行独立的操作, ...

  4. [LeetCode] Super Washing Machines 超级洗衣机

    You have n super washing machines on a line. Initially, each washing machine has some dresses or is ...

  5. [Swift]LeetCode517. 超级洗衣机 | Super Washing Machines

    You have n super washing machines on a line. Initially, each washing machine has some dresses or is ...

  6. LeetCode517. Super Washing Machines

    You have n super washing machines on a line. Initially, each washing machine has some dresses or is ...

  7. [LeetCode] 313. Super Ugly Number 超级丑陋数

    Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all ...

  8. Java实现 LeetCode 517 超级洗衣机

    517. 超级洗衣机 假设有 n 台超级洗衣机放在同一排上.开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的. 在每一步操作中,你可以选择任意 m (1 ≤ m ≤ n) 台洗衣机,与此同时将 ...

  9. Leetcode 313. super ugly number

    Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all ...

随机推荐

  1. leetCode58. 最后一个单词的长度

    给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度. 如果不存在最后一个单词,请返回 0 . 说明:一个单词是指由字母组成,但不包含任何空格的字符串. 示例: 输入: &quo ...

  2. Vue.js中记不住 的东西

    给样式背景赋值: :style="{backgroundImage:'url(' + otherInfo.head_image + ')'}" <img :src=" ...

  3. qt qextserialport __imp_SetupDiGetDeviceRegistryPropertyW

    使用 qextserialport 编写串口助手的时候,提示找不到 __imp_SetupDiGetDeviceRegistryPropertyW,经过摸索有以下两种解决方法: 第一种: 把相应的源文 ...

  4. 团队作业-Week9-软件项目的风险

    一.软件项目中的风险 软件项目的风险无非体现在以下四个方面:需求.技术.成本和进度.IT项目开发中常见的风险有如下几类: (1)需求风险 ①需求已经成为项目基准,但需求还在继续变化: ②需求定义欠佳, ...

  5. 2. spring定时任务

    1.添加命名空间 <!-- 定时注解驱动 --> <task:annotation-driven /> <!-- 进行定时任务的类,将其定义为一个bean --> ...

  6. mongodb集群部署

    一.安装Mongodb(Tarballs) 1.检查依赖文件包: yum install libcurl openssl 2.解压文件到/usr/local/ tar -zxvf mongodb-li ...

  7. vue.js响应式原理解析与实现

    vue.js响应式原理解析与实现 从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很 ...

  8. jeecg-boot 简易部署方案

    jeecg-boot采用前后端分离的方案,前后端代码不在一起.想要部署 一般是通过反向代理实现. jeecg-boot目前支持更好更简单的解决方案: jeecg 在配置文件里面指定了 webapp的存 ...

  9. vue中less文件全局引用

    1.先安装sass-resources-loader   npm install sass-resources-loader 2.然后在build->utils.js修改less配置 在less ...

  10. python day06笔记总结

    2019.4.3 S21 day06笔记总结 一.昨日内容补充 1.列表独有功能: 1.revers 反转 例:v1 = [1,2,4,88,2] v1.revers() print(v1) 2.so ...