uva 11300 Spreading the Wealth

Posted Omz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uva 11300 Spreading the Wealth相关的知识,希望对你有一定的参考价值。

https://vjudge.net/problem/UVA-11300

题意:

圆桌旁坐着n个人,每个人有一定数量的金币,金币总数能被n整除。每个人可以给他左右相邻的人一些金币,最终使得每个人的金币数量相等。你的任务是求出被转手金币数量的最小值。当n = 4,4个人的数量分别为1,2,5,4,最小值是4枚金币,3给2两枚,2和4分别给1一个金币。

思路:

首先,金币的平均数可以计算出来,假设为m。

假设有4个人,编号为1,2,3,4。假设1号给2号3枚,2号给1号5枚,那么相当于2号给1号2枚,所以重复的只会增加金币的数量,无意义。所以,设x2表示2号给了1号多少个金币,那么x1表示1号给了4号多少枚金币。

这时,所有人的金币数量都可以计算出来

a1 - x1 + x2 = m

a2 - x2 + x3 = m

......

an-1 - xn-1 + xn = m

可以列出n - 1个式子,第n个式子没有意义,它可以由n - 1个式子相加得到。

之后,对每个式子做一定的变换

x2 = x1 - c1

x3 = x1 - c2

......

xn = x1 - cn-1

 

然后,根据这些式子,进一步推出ci 与 ci-1的关系是 ci = ci-1 + ai -m。

我们希望所有xi的绝对值之和最小(xi表示转手的金币数),因为每一个xi都可以用x1表示,所以,我们实际求的是

|x1| + |x1 - c1| + |x1 - c2| + ...... + |x1 - cn-1|

这时候对问题进行数学抽象,就得到了问题:

给定数轴上的n个点,找出一个点使得所有的点的距离到它的距离最小。

可以猜测这个最优的点是这些点的中位数,所以我们把c这个数组排序取中间就可以了。(具体证明见训练指南)

代码:

#include <stdio.h>
#include <algorithm>
using namespace std;

long long c[1000005];
long long a[1000005];
int main()
{
    int n;

    while (scanf("%d",&n) != EOF)
    {
        long long sum = 0;

        for (int i = 1;i <= n;i++)
        {
            scanf("%lld",&a[i]);
            sum += a[i];
        }

        c[0] = 0;

        long long m = sum / n;

        for (int i = 1;i < n;i++) c[i] = c[i-1] + a[i] - m;

        sort(c,c+n);

        long long x = c[n / 2];

        long long ans = 0;

        for (int i = 0;i < n;i++) ans += abs(c[i]-x);

        printf("%lld\n",ans);
    }


    return 0;
}

 

以上是关于uva 11300 Spreading the Wealth的主要内容,如果未能解决你的问题,请参考以下文章

Uva 11300 Spreading the Wealth 中位数

UVA11300 Spreading the Wealth水题

UVa 11300 Spreading the Wealth(有钱同使)

uva 11300 Spreading the Wealth

Uva 11300 Spreading the Wealth(贪心)

UVa11300 - Spreading the Wealth