uva 11300
分类: 中位数与排序统计学
题意: N个人每个人有Ai个金币,综合整除N,每个人可以给相邻的人一定数量的金币(圆环)
如何给使得金币流动数最少,而且每个人最后金币数量一样
输入: N,每个人金币Ai
输出: 最小的金币流通数目
解法: 设Xi为第i个人给第i-1个人的金币数,x1表示第一个人给第四个人,只设置单方向(双向可以抵消)
列方程组 A1 - X1 + X2 = M
.
.
Ai-1 - Xi-1 + Xi+1 = M
有n-1个方程组, Ai和M是常数
优化目的 sigma(|xi|)最小,简化方程 C1 = A1 - M C2 =A1 + A2 - 2M = A2 + C1 - M(转化为只和X1相关, 解n-1个方程的方程组)
X2 = X1 - C1
X3 = X1 - C2
Ci皆为常数,采用中位数
#include <iostream> #include <vector> #include <map> #include <list> #include <set> #include <deque> #include <stack> #include <queue> #include <algorithm> #include <cmath> #include <cctype> #include <cstdio> #include <iomanip> #include <cmath> #include <cstdio> #include <iostream> #include <string> #include <sstream> #include <cstring> #include <queue> using namespace std; ///宏定义 const int INF = 990000000; const int MAXN = 1000010; const int maxn = MAXN; ///全局变量 和 函数 typedef long long LL; LL n, tot, M, ans; LL arr[MAXN], C[MAXN]; LL ababs(LL x1) { if (x1 > 0) return x1; else return -x1; } int main() { ///变量定义 while (scanf("%lld", &n) != EOF) { tot = ans = 0; for (int i = 1; i <= n; i++) { LL temp; scanf("%lld", &temp); tot += temp; arr[i] = temp; } M = tot / n; //递推n - 1次 C[0] = 0; for (int i = 1; i < n; i++) { C[i] = C[i - 1] + arr[i] - M; } //寻找中位点 核心部分 sort(C + 1, C + n); LL xi = C[n / 2]; for (int i = 0; i <= n - 1; i++) { ans += ababs(xi - C[i]); } printf("%lld\n", ans); } ///结束 return 0; }