平分糖果---2013阿里笔试题

/*
有n个小朋友坐成一圈,每人有Ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1,求使所有人获得均等糖果的最小代价。
假设当前n个小朋友手中的糖果数量是
a[ 1 ] , a[ 2 ] , ...... , a[ n ]
那么总共的糖果量是
sum_ = a[ 1 ] + a[ 2 ] + ...... + a[ n ]
平均值,即传苹果结束的时候每个人手中剩余苹果量是:
average = sum / n
第一步,第1个小朋友给了第n个小朋友k(可能为正、负、0)个苹果(暂且不要管为什么这样,只需要他这么做了)
付出代价是|k|
这时候第1个小朋友手中的苹果数量是:
a[ 1 ] - k

第二步,为了保证第1个小朋友手中苹果为average,需要从第2个小朋友中拿,拿多少呢?
average-(a[1]-k)= average-a[1]+k
付出代价是
| average-a[1]+k |
第2个小朋友剩下多少呢
a[2]-( average-(a[1]-k) )=a[2]+a[1]-average-k

第三步,为了保证第2个小朋友手中苹果为average,需要从第3个小朋友中拿,拿多少呢?
average-( a[2]+a[1]-average-k ) = 2*average-a[1]-a[2]+k
付出代价是
|2*average-a[1]-a[2]+k|
第3个小朋友剩下多少呢
a[3]-( 2*average-a[1]-a[2]+k ) = a[3]+a[2]+a[1]-2*average-k

第N步,为了保证第N-1个小朋友手中苹果为average,需要从第N个小朋友中拿,这时候付出的代价是
|a[n-1]+a[n-2]+......+a[2]+a[1]-n*average-k|

显然,这时候第n个位置剩余苹果数也是average,因为n-1个位置都是average了,只有一个average剩下,即在第n个位置
经过上面分析,总共需要付出的代价是
 |k|
+|average-a[1]+k|
+|2*average-a[1]-a[2]+k|
+
.
.
.
+
|n*average+k-a[n-1]-a[n-2]-......-a[2]-a[1]|

或者表示为

S=
 |k|
+|(a[1]-average)-k|
+|(a[1]-average)+(a[2]-average)-k|
+
.
.
.
+
|(a[1]-average)+(a[2]-average)+......+(a[n-1]-average)-k|

假设有一个数组b,其内容分别是
b[1]   = 0
b[2]   = (a[1]-average)
b[3]   = (a[1]-average)+(a[2]-average)
.
.
.
b[n]   = (a[1]-average)+(a[2]-average)+......+(a[n-1]-average)

那么b数组就可以表示成数轴上面的n个点
S就可以表示“在数轴上选一个点k,数组b中每个元素对应的点到点k的距离的和”
这个点k应该是多少呢?应该是数组b的中位数,求出中位数,即可得出最小的S。
这个k的有效取值范围是多少呢?我自己觉得是[-a[n],a[1]],即最多1把自己全部苹果给n;最小,n把全部苹果给1
这个利用了中位数一个性质
*/

//假设n可以整除所有苹果的总和

#include<algorithm>
#include<iostream>
using namespace std;

int main() {
	int a[ 100 ];
	int b[ 100 ];
	int n;
	int i;
	int sum = 0;
	int average = 0;
	int mid = 0;
	int result = 0;
	scanf( "%d" , & n );
	for( i = 1 ; i <= n ; i ++ ) {
		scanf( "%d" , & a[ i ] );
		sum += a[ i ];
	}
	//求平均值
	average = sum / n;
	cout << average << endl;
	//求数组b
	b[ 1 ] = 0;
	for( i = 2 ; i <= n ; i ++ ) {
		b[ i ] = b[ i - 1 ] + a[ i - 1 ] - average;
	}
	//排序,为了求中位数
	sort( b + 1, b + n + 1 );
	//求中位数
	if( n % 2 == 0 ) {
		mid = ( b[ ( n + 1 ) / 2 ] + b[ ( n + 1 ) / 2 - 1 ] ) / 2;
	}
	else {
		mid = b[ ( n + 1 ) / 2 ];
	}
	//求代价
	for( i = 1 ; i <= n ; i ++ ) {
		result = result + abs( mid - b[ i ] );
	}
	cout << result << endl;
	return 1;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值