付账问题(贪心)

此题来源自蓝桥杯。

问题描述:

几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。

现在有 nn 个人出去吃饭,他们总共消费了 S 元。其中第 i 个人带了 ai​元。幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?

为了公平起见,我们希望在总付钱量恰好为 S 的前提下,最后每个人付的钱的标准差最小。这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是 1 分钱的整数倍。你需要输出最小的标准差是多少。

标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的"偏差有多大"。形式化地说,设第 i个人付的钱为 bi​ 元,那么标准差为 :

输入描述

付账问题(贪心)_第1张图片

输出描述

付账问题(贪心)_第2张图片

代码如下:

//贪心策略求解,先从小到大进行排序, 如果排序后第一个人的前数少于S/n,则为了减小标准差,此人应拿出所有的钱,
//如果第一个人的钱大于S/n,则后面所有人的钱数都大于S/n,此时每个人都出S/n即可。
//对于第二个人也是这样考虑,只是S和n的值可能会改变。
//后面所有的人都这样进行考虑。 


#include
#include
#include
using namespace std;

const int N=5e5+10;
long long a[N]; //题目中虽然说到ai用int类型既能存储,但这里要定义为long long ,因为下面有语句a[i]*(n-i+1)>=S,该语句左边可能是long long 

int main(){
	int n;
	long long S; //S可能为 long long 类型 
	cin>>n>>S;
	double avg=S*1.0/n; //不要忘记乘以1.0 
	double r_avg;
	double ans=0; 
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	} 
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		if(a[i]*(n-i+1)>=S){
			r_avg=S*1.0/(n-i+1);
			ans+=(r_avg-avg)*(r_avg-avg)*(n-i+1);
			break;
		}
		else{
			S-=a[i];
			ans+=(a[i]-avg)*(a[i]-avg);
		}
	}
	printf("%.4lf",sqrt(ans*1.0/n));
	return 0;
} 

你可能感兴趣的:(算法)