1235. 付账问题 Java题解 (贪心)【第九届蓝桥杯省赛C++A组,JAVA A组】

35 篇文章 2 订阅
10 篇文章 0 订阅

输入样例1:

5 2333
666 666 666 666 666

输出样例1:

0.0000

输入样例2:

10 30
2 1 4 7 4 8 3 6 4 7

输出样例2:

0.7928

解题思路:

要想使得标准差最小,即方差最小,应使得所有人的付账波动不能太大,理想状况是每人应该出正好平均值的钱,这样方差就是0。但是,当有人不够平均值时,就需要将他所有的钱都结付,尽可能的接近平均值,那这个人不够的部分就需要其他人来补上了,为了使每人出的钱都接近平均值,所以补的这部分需要“有能力担负的起的人”共同均摊。

支付时,应该先考虑钱拿的最少的,这样就算不够了后面也有人补贴,所以就需要给数组排序。当遍历到某个人时,如果发现钱不够平均值,就需要重新计算加上补贴这个人的平均值;如果发现他的钱已经不少于所需支付的平均值了,说明他之后的人钱数都已经足够了,为了确保精度,此时剩下人的平均值可以直接算出来,就不再需要再重复计算了。

Java代码:

import java.io.*;
import java.util.Arrays;

public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] split = br.readLine().split(" ");
		int n = Integer.parseInt(split[0]);
		double s = Double.parseDouble(split[1]);
		int []arr = new int[n];
		split = br.readLine().split(" ");
		for(int i = 0; i < n; i++)
			arr[i] = Integer.parseInt(split[i]);
		
		Arrays.sort(arr);
		
		double avg = s / n;  // 理论上每人应付的钱
		double res = 0;  // 方差
		boolean flag = false;  // 标志到某以个人时,是否之后的都足够结账
		for(int i = 0; i < n; i++) {
			double x = s / (n - i);  //  当前平均值
			if(arr[i] >= x) flag = true;
			if(arr[i] < x) x = arr[i];  //  不够时,尽可能“多凑”
			s -= x;   // 剩下的人还需要结账的总数
			if(!flag) res += (x - avg) * (x - avg);  //  累加方差
			else {
				res += (x - avg) * (x - avg) * (n - i);
				break;
			}
		}
		System.out.printf("%.4f", Math.sqrt(res / n));
	}
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值