EOJ-2927 负载平衡问题
链接: http://www.acm.cs.ecnu.edu.cn/problem.php?problemid=2927
这道题用了均分纸牌的方法
开始容易想到在所有的仓库中找到最多的库存量,然后向小的仓库移动,一直到所有的货物都相等,但关键是不知道往哪个方向上移动才能达到移动次数最少。设a[i]为第i个仓库的库存量(0<=i<=n),ave为均分后每个仓库的库存量,ans为最小移到次数。我们按照由左而右的顺序移动货物。若第i个仓库的库存量a[i]超出平均值,则移动一次(ans+1),将超出部分留给下一个仓库,既第i+1个仓库的库存量增加a[i]-ave;若第i个仓库的库存量a[i]少于平均值,则移动一次(ans+1),由下一个补充不足部分,既第i+1个仓库的库存量减少ave-a[i];
问题是,在从第i+1个仓库中取出货物补充第i个仓库的过程中,可能会出现第i+1个仓库的货物数小于零(a[i+1]-(ave-a[i])<0)的情况,但由于货物的总数是n的倍数,因此后面的仓库会补充第i+1个仓库ave-a[i]-a[i+1]+ ave个货物,使其达到均分的要求。我们在移动过程中,只是改变了移动的顺序,而移动的次数不变,因此此题使用该方法是可行的。
例如:1 2 27
我们从第三堆移出8个到第二堆后,第二堆有10个货物,第三堆剩下19张货物,再从第三堆移动9个到第一堆,刚好三堆货物数都是10,最后结果是对的,一共需要17次移动
此题的原理是贪心,每次使左边的货物达到平均值,最终由n个不同的开始有n种不同的答案,遍历一遍取最小值即为所求值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cmath> 3 using namespace std; 4 5 int n, a[105], ans, ave; 6 7 int main() 8 { 9 while (cin >> n) 10 { 11 int s = 0; 12 ans = 99999; 13 for (int i = 0; i < n; i++) 14 { 15 cin >> a[i]; 16 s += a[i]; 17 } 18 ave = s/n; 19 for (int i = 0; i < n; i++) 20 a[i] -= ave; 21 for (int i = 0; i < n; i++) 22 { 23 int t = 0, x = 0; 24 for (int j = 0; j < n - 1; j++) 25 { 26 t += a[(j + i)%n]; 27 x += abs(t); 28 } 29 ans = min(x, ans); 30 } 31 cout << ans << endl; 32 } 33 return 0; 34 }