EOJ2927 负载平衡问题

链接: 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种不同的答案,遍历一遍取最小值即为所求值。

 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 }
View Code
原文地址:https://www.cnblogs.com/KimKyeYu/p/3128685.html