517. 超级洗衣机
题目
假设有 n 台超级洗衣机放在同一排上。开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的。
在每一步操作中,你可以选择任意 m (1 ≤ m ≤ n) 台洗衣机,与此同时将每台洗衣机的一件衣服送到相邻的一台洗衣机。
给定一个非负整数数组代表从左至右每台洗衣机中的衣物数量,请给出能让所有洗衣机中剩下的衣物的数量相等的最少的操作步数。如果不能使每台洗衣机中衣物的数量相等,则返回 -1。
示例 1:
输入: [1,0,5]
输出: 3
解释:
第一步: 1 0 <-- 5 => 1 1 4
第二步: 1 <-- 1 <-- 4 => 2 1 3
第三步: 2 1 <-- 3 => 2 2 2
思路
首先,计算所有机器上的任务数量总和sum,如果sum%n结果不为0,说明是无解的。如果有解,那么最终,每个机器上的任务数应该是sum/n,记为avg。
遍历所有的机器,每一个机器i,都要考虑以下的情况。设i之前的所有机器是L,i之后的所有机器是R,L和R都是不包括i的。那么,这里S_L表示L上所有任务的总和,S_R表示R上所有任务的总和。那么S_L-avg*l(l表示L上的机器数量)就是L这个整体需要向外发送或者接收的任务数量。对于S_R,同理。对于机器i,i-avg就是机器i所需要向外发送或者接收的任务数量。
例如,S_L=30,i-avg=10,S_R=-40,那么L和机器i就总共需要向R传40个任务,至少需要40轮才能发送完。
这里就出现了四种情况。
1、S_L>0 and S_R>0 :
这时候,i-avg必然是小于0的,说明L和R都需要向i发送多余的任务,那么轮数就是max(S_L,S_R)
2、S_L<0 and S_R<0:
这时候,i-avg必须是大于0的,说明i需要向L和R发送,但是i每次只能发一个,所以轮数就是i-avg
3、S_L< 0 and S_R > 0:
这时候,不需要管i-avg的值了,最大绝对值的那个就是轮数,而这个最大绝对值,必然出现在S_L和S_R中,否则就矛盾了。轮数就是max(abs(S_L),abs(S_R))
4、S_L>0 and S_R < 0:
和3同理,轮数就是max(abs(S_L),abs(S_R))
综上,可以将四种情况合并,得到两种:
1、S_L<0 and S_R<0:
轮数就是i-avg
2、其余情况
轮数就是max(abs(S_L),abs(S_R))
遍历所有的i,找到最大的轮数,就是最终的结果。
至于算法的正确性,不会证,应该和最大网络流什么的相关,就算了吧
代码
public int findMinMoves(int[] machines) {
int n = machines.length;
int sum = 0;
for(int i:machines){
sum = sum+i;
}
if(sum%n!=0){
return -1;
}
int avg = sum/n;
int ans = 0;
int left_sum = 0;
for(int i=0;i<n;i++){
int left_rest = left_sum - i*avg;
int right_rest = (sum - left_sum -machines[i]) - (n-i-1)*avg;
if(left_rest<0 && right_rest<0){
ans = Math.max(ans,Math.abs(left_rest)+Math.abs(right_rest));
}else{
ans = Math.max(ans,Math.max(Math.abs(left_rest),Math.abs(right_rest)));
}
left_sum = left_sum + machines[i];
}
return ans;
}
补充
这题比较难,感觉思路拓展性有限,可能只适合这个题。另外标签有动态规划,但是没看出来