Spreading the Wealth(Uva 11300)单变量极值问题

Problem Description

A Communist regime is trying to redistribute wealth in a village. They have have decided to sit everyone around a circular table. First, everyone has converted all of their properties to coins of equal value, such that the total number of coins is divisible by the number of people in the village. Finally, each person gives a number of coins to the person on his right and a number coins to the person on his left, such that in the end, everyone has the same number of coins. Given the number of coins of each person, compute the minimum number of coins that must be transferred using this method so that everyone has the same number of coins.

Input

There is a number of inputs. Each input begins with n (n < 1000001), the number of people in the village. n lines follow, giving the number of coins of each person in the village, in counterclockwise order around the table. The total number of coins will fit inside an unsigned 64 bit integer.

Output

For each input, output the minimum number of coins that must be transferred on a single line.

Sample Input

3
100
100
100
4
1
2
5
4

Sample Output

0
4

题目大体意思是:
现在有n个人坐在一个圆桌的周围,每个人有一定数量的金币,并且金币总数能够被n整除,每个人可以给相邻的人金币;现在要求开始与相邻的人通过给金币,达到最后每个人拥有的金币数目都相同的结果时算完成。
输入:
包含多组数据,每组数据第一行为整数n(n<=1 000 000), 以下n行每行为一个整数,按照逆时针顺序给出每个人拥有的金币数,输入结束标志为EOF
输出:
对每一组输入数据,输出被转手金币数量的最小值;输入保证这个值在64为无符号整数范围内;

解答:

假设最终计算出每个人拥有的金币数量为T,因为每个人都只能与身边相邻的两人进行交换金币,所以考虑定义x[i],其含义为第i个人给第i-1个人的金币数量,特别的当i=1时表示 第一个人给第n个人的金币数量;例如x[2]=-2的含义就是第2号给了第1号-2个金币,也就是第1号给了第2号2个金币;再假设A[i]表示第i个人初始金币的个数,那么我们容易得出:

A[i] - x[i] + x[i+1] = T (1 <= i <= n-1)
A[n]-x[n] + x[1] = T

  • 总共n个方程,但是因为最后一个方程是能够通过其他方程求出的,所以正真有用的是n-1个方程,无法解出所有的未知数;
  • 但是我们不需要知道所有的未知数,因为这个题目的x的解本来就是不唯一的,我们只要求出转手的金币数量的最小值就可以了。
  • 转移的金币数量总数为所有的x[i]绝对值的和,从上面的方程中可以发现,可以将其它的n-1个x用x[1]来表示:

    x[i] = x[1] - ( A[i] + A[i-1] + A[i-2]+ … + A[1] - T )

为了简化,括号内记为C[i]
那么就可以仅用x[1]去表示所有的x的绝对值:
abs(x1) + abs(x1 - C1) + abs( x1 - C2) +……+ abs(x1 - C[n-1])
容易发现,其实就是找一个点使它到所有的C[i]的距离之和最小,所以最优的x1就是这些数的中位数。

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

const int maxn = 1000000 + 10;
long long A[maxn], C[maxn], tot, T;


int main()
{
    int n;
    while(scanf("%d", &n) == 1){
        tot = 0;
        long long tmp;
        C[0] = 0;
        for(int i = 1; i<=n; i++){
            scanf("%lld", &tmp);
            tot += tmp;
            if(i>=1){
                C[i] = C[i-1] + tmp;
            }
        }
        T = tot/n;  //the average amount of coins everyone should have at the end of the procdure.


        for(int i = 1; i<n ; i++){
            C[i] -= i*T;
        }
        sort(C, C+n);
        long long x = C[n/2], ans = 0;

        for(int i = 0; i<n ; i++){
            ans+=abs(x - C[i]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

16265715 11300 Spreading the Wealth Accepted C++ 0.132 2015-10-14 12:01:52

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值