今天开始定期记录本人在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. C# 使用缓存数据模拟抢购

      在所有的电商网站中,不乏大量的抢购,比如双十一,双十二等等,作为一名开发人员考虑最多的就是多并发以及高并发 废话少说,开始写代码.我用了C#的MemoryCache代替试下流行的各种缓存 商品测试 ...

  2. 域名动态解析到动态IP

    一般宽带用户的IP都是动态IP,重连之后IP可能会发生变化. 如果想在其他地方连接家里的设备,或者在家中搭建服务器,就会受到影响. 现在提供一种动态解析域名的方式,只要检测到IP的变化,那么就调用阿里 ...

  3. command not found所有执行命令总是报找不到

    输入 ll命令 提示: bash: ls: 未找到命令…  相似命令是: 'lz' 原因: 环境变量PATH被修改了 解决办法: 执行: export PATH=/bin:/usr/bin:$PATH ...

  4. Linux充电站

    [Ansible中文权威指南] [鸟哥的linux私房菜] AWK使用手册 Centos的epel源下载 Ceph国内社区 chef简明手册 ChinaUnix运维文库 Confluence和Jira ...

  5. QTP测试.NET程序的时候,找不到对象或无法录制的解决方案

    解决方案: .NET程序编译的时候:目标平台必须设置为x86,否则QTP找不到对象,不会完成录制

  6. html页面嵌套两个iframe页面导致第二个iframe页面高度失效的问题

    1:这是因为最里面嵌套的iframe页面html和body高度无法设置问题,我的解决办法是js去控制iframe高度 2:js获取最子页面(content内容区域)的高度 var ifremHeigh ...

  7. Windows服务器

    知道了怎么装VMware workstation并且创建虚拟机装上了系统配好网络

  8. thinkphp51初始化方法initialize

    此方法是在所有方法之前被调用的. class Index extends Controller { public function _initialize() { echo 'init<br/& ...

  9. Centos7 操作系统 mysql5.7 配置远程登陆操作

    Centos7 操作系统: mysql5.7 配置远程登陆操作: 首先登陆服务器,进入数据库: mysql -u root -p show databases; use mysql; show tab ...

  10. Redis 4.0.2.3 for Windows (alpha) 下载地址

    下载地址如下: https://github.com/tporadowski/redis/releases 如果直接使用redis-server.exe启动报错的话,就使用redis-server.e ...