今天开始定期记录本人在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. request和response的常用方法

    一.request   1.setAttribute()在Request域中存储数据  2.setCharacterEncoding()设置请求参数的编码方式,只对post请求有效  3.getMet ...

  2. python--面向过程编程与面向对象编程

    面向过程 面向过程: 核心就是过程二字,过程指的是解决问题的步骤,设计一条流水线,机械式的思维方式. 优点: 复杂的问题流程化,进而简单化. 缺点: 可扩展性差. 面向对象 面向对象: 核心就是对象二 ...

  3. Linux 总线、设备、驱动模型 与 设备树

    1.总线.设备.驱动模型 本着高内聚.低耦合的原则,Linux 把设备驱动模型分为了总线.设备和驱动三个实体,这三个实体在内核里的职责分别如下: 设备和驱动向总线进行注册,总线负责把设备和对应的驱动绑 ...

  4. pytorch 生成随机数

    在使用PyTorch做实验时经常会用到生成随机数Tensor的方法,比如: torch.rand() torch.randn() torch.normal() torch.linespace() 在很 ...

  5. requests和session的区别

    简单说 request对象和session对象的最大区别是生命周期. -request request对象的生命周期是针对一个客户端(说确切点就是一个浏览器应用程序)的一次请求,当请求完毕之后,req ...

  6. golang基于etcd实现分布式锁(转)

    下面描述使用 Etcd 实现分布式锁的业务流程,假设对某个共享资源设置的锁名为:/lock/mylock 步骤 1: 准备 客户端连接 Etcd,以 /lock/mylock 为前缀创建全局唯一的 k ...

  7. mkdir npm

    mkdir -p 创建目录 没有就创建 有就用 npm init -y 不提示创建package.json 文件

  8. c# WinForm 文本输入对话框

    这种功能为什么不向MessageBox一样自带,还得自己写~~ 代码: public InputBox(string label) { InitializeComponent(); label1.Te ...

  9. R和Python,对抗or融合?

    来源商业新知网,原标题:从对抗到融合,教你充分利用R+Python! 我们应该将关注点放在技能上,而不是工具上. 如果你从事数据科学的工作,可能会立即想到两种编程语言:R和Python. 事实上,R和 ...

  10. 浅谈Spring

    参考文章: https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/ 参考书籍: <SPRING技术内幕:深入解析SPR ...