今天开始定期记录本人在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. skynet框架之日程表设计

    参考云风大神的例子,对其进行了改进,支持多次提交单个日程,改变时间后,提前日程触发时间. --[[ t提供了两种方案 方案1和2 ]] local skynet = require "sky ...

  2. 2018-2019-2 20165205 网络攻防Exp3免杀原理与实践

    2018-2019-2 20165205 网络攻防Exp3免杀原理与实践 一.实践内容 1.1正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,加壳工具,使用 ...

  3. leetcode每日刷题计划-简单篇day10

    跳题,不熟悉的留到周末再做. 保持冷静,不信画饼. num 100 相同的树 Same Tree 做法可能不是特别简洁,注意一下.最后判断完子树以后,要确定根的数值是一样的 然后在isleaf的判定先 ...

  4. LeetCode 147. Insertion Sort List 链表插入排序 C++/Java

    Sort a linked list using insertion sort. A graphical example of insertion sort. The partial sorted l ...

  5. Linux命令、脚本

    1.传文件 FTP/SFTP:ftp 用户名@远程ip SCP:注意ip后有个   : 本地文件发到远程 scp 本地文件 用户名@远程ip:远程路径   远程文件发到本地 scp 用户名@远程ip: ...

  6. PHP截取特定字符串前后

    $email   =  '13366540193@163.com' ;$domain  =  strstr ( $email ,  '@' );echo  $domain ;  // 打印 @163. ...

  7. appium 使用环境安装配置记录

    一.安装配置Java (cmd输入java,回车,没有出现“不是内部或外部命令,也不是可运行的程序或批处理文件”,即为成功) 二.安装node.js (cmd输入node -v,显示版本号即为成功) ...

  8. assert (boxes[:, 2] >= boxes[:, 0]).all()报错

    根据报错信息,打印以下内容: 代码如下: for i in xrange(num_images): #print ('in append_flipped==================',self ...

  9. redis bind的坑

    启动redis时,发现外网访问不了 检查以下方面 1. ping redis 的ip 2. 检查防火墙端口是否开放3. bind bind bind指的是绑定哪个ip可以访问 bind 要填写你自己r ...

  10. hibernate的开始

    1.1对象的持久化 对象持久化是指将内存中的对象保存到可永久保存的存储设备中(如磁盘)的一种技术.(hibernate是通过id来管理对象) 1.2怎样实现持久化 1 对象序列化 2 JDBC 3 O ...