UVA 11300 Spreading the Wealth
题目大意:n个人手中有些金币,每个人可给相邻两个人一些金币,使得最终每个人手中金币数相同,求被转手的金币最少数
m为最终每个人手中的金币数,a1,a2,a3,...,an为每个人开始时手中的金币数,x1,x2,x3,...,xn为每个人转手的金币数
- 假设 4个人 号分别为 1 2 3 4
x2 :为2号给1号的金币数
x3 :为3号给2号的金币数
x4 :为4号给3号的金币数
x1 :为1号给4号的金币数
设:c1 = a1 - m(即:cn = an - m);
C1 = c1 = a1 - m;
C2 = c1 + c2 = C1 + c2 = C1 + a2 - m;
C3 = c1 + c2 + c3 = C2 + c3 = C2 + a3 - m;
...
Cn = C(n - 1) + an - m;
1号 :m = a1 + x2 - x1; x2 = m + x1 - a1 = x1 - c1 = x1 - C1;(1号最终所得金币为其原有的金币加上2号所给的减去其给4号的金币所得,下面同理)
2号 :m = a2 + x3 - x2; x3 = m + x2 - a2 = x2 - c2 = x1 - c1 - c2 = x1 - C2;
3号 :m = a3 + x4 - x3; x4 = m + x3 - a3 = x3 - c3 = x1 - c1 - c2 - c3 = x1 - C3;
...
xn = x1 - C(n - 1);
求转手金币的最小值(即求x1 + x2 + x3 +...+xn的最小值即求x1+|x1-C1|+|x1-C2|+|x1-C3|+...+|x1-C(n-1)|的最小值)
其几何意义为求一个点到n个点距离和的最小值(即数轴上点x1到Ci的距离和的最小值)
若想使其距离和最小,则x1需满足的条件是:点x1必须为n个点中的中位数
若点数n为奇数则点x1必须与中间那个点重合(即中位数)
若点数n为偶数则点x1必须在中间两个点之间(仍是中位数)
#include<stdio.h> #include<math.h> #include<stdlib.h> #define N 1000010 long long a[N], c[N], sum, ans, m, x1; int cmp(const void *a, const void *b) { return *(int *)a - *(int *)b; } int main() { int n, i; while(scanf("%d", &n) != EOF) { sum = ans = 0; for(i = 0 ; i < n ; i++) { scanf("%lld", &a[i]); sum += a[i]; } m = sum / n; c[0] = 0; for(i = 1 ; i < n ; i++) c[i] = c[i - 1] + a[i] - m; qsort(c, n, sizeof(c[0]), cmp); x1 = c[n / 2]; for(i = 0 ; i < n ; i++) ans += fabs(x1 - c[i]); printf("%lld\n", ans); } return 0; }