1432. 糖果传递

信息学奥赛一本通 贪心算法

【题目描述】

有nn个小朋友坐成一圈,每人有aiai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。

【输入】

第一行一个正整数n≤1000000,表示小朋友的个数.

接下来n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.

【输出】

求使所有人获得均等糖果的最小代价。

【输入样例】

4
1
2
5
4

【输出样例】

4

【分析】

本题网上有许多题解,这里对于一些细节做一下阐述,以方便理解代码。

用x1...xn表示i小朋友给左边小朋友的糖果数量,正数为给予,负数为索取。根据分析可以列出一系列式子。

当前小朋友手头的糖果 - 给左边的糖果 + 右边给的糖果 = 平均值

a1 - x1 + x2 = average ==> x2 = x1 + average - a1 ==> x2 = x1 - (a1 - average)

a2 - x2 + x3 = average ==> x3 = x2 + average -a2  ==> x3 = x2 - (a2 - average) 

......

最终可以写成如下的式子:                      在数组c中存放了x1减号后面的一系列值,第一个数是0

x1 = x1 - 0                                                 ==>c[1] = 0

x2 = x1 - (a1 - average)                            ==>c[2] = c[1] + a[1] - average

x3 = x1 - (a1 -average + a2 - average)     ==>c[3] = c[2] + a[2] - average

......

xn = x1 - (a1 + ... an-1 - (n-1)*average)    ==>c[n] = c[n-1] + a[n-1] - average

c[1] = 0;
	for(int i = 2; i <= n; i++){
		c[i] = c[i-1] + a[i-1] - average;
	}

x1 + x2 + x3 +...+ xn的值最小,即移动代价最小才符合题目要求,题目求解转化为求点到所有点之间的距离和。先排序,取中位数点进行计算。

int mid = c[n / 2 + 1];
	//求点到所有点之间的距离和
	for(int i = 1; i <= n; i++){
		ans += abs(c[i] - mid);
	}

【完整代码】

#include <bits/stdc++.h>

long long a[1000005],c[1000005];
using namespace std;
int main(int argc, char *argv[]) {
	int n;
	long long sum = 0;
	cin >> n;
	for(int i  = 1; i <= n; i++){
		cin >> a[i];
		sum += a[i];
	}
	//计算平均值
	int  average = sum / n;
	
	/*
	x1...n表示i小朋友给左边小朋友的糖果数量,正数为给,负数为索取
	当前小朋友手头的糖果 - 给左边的糖果 + 右边给的糖果 = 平均值
	a1 - x1 + x2 = average ==> x2 = x1 + average - a1 ==> x2 = x1 - (a1 - average)
	......
	......
	最终可以写成如下的式子:                      ==>在数组c中存放了x1减去的一系列值,第一个数是0
	x1 = x1 - 0                               ==>c[1] = 0
	x2 = x1 - (a1 - average)                  ==>c[2] = c[1] + a[1] - average
	x3 = x1 - (a1 -average + a2 - average)    ==>c[3] = c[2] + a[2] - average
	......
	xn = x1 - (a1 + ... an-1 - (n-1)*average) ==>c[n] = c[n-1] + a[n-1] - average
	*/
	c[1] = 0;
	for(int i = 2; i <= n; i++){
		c[i] = c[i-1] + a[i-1] - average;
	}
	/*
	x1 + x2 + x3 +...+ xn的值最小,即移动代价最小才符合题目要求,转化为求点到所有点之间的距离和。
	先排序,取中位数点进行计算。
	*/
	//升序
	sort(c+1, c + n +1);
	
	long long  ans = 0;
	//队列的中位数
	int mid = c[n / 2 + 1];
	//求点到所有点之间的距离和
	for(int i = 1; i <= n; i++){
		ans += abs(c[i] - mid);
	}
		cout << ans;
	return 0;
		
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值