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;
}

 

posted on 2013-09-16 17:44  小书包_Ray  阅读(150)  评论(0编辑  收藏  举报

导航