信息学奥赛一本通 1229:电池的寿命 | OpenJudge NOI 4.6 2469:电池的寿命

【题目链接】

ybt 1229:电池的寿命
OpenJudge NOI 4.6 2469:电池的寿命

【题目考点】

1. 贪心

【解题思路】

1. 贪心选择性质的证明

电池分配主要有两步,
第一步:将电池分为两组,使两组电池的总使用时长的差值尽可能小。
第二步:如果总时长更长的分组中有多于1个电池,那么取出这一组中的一些电池运行游戏机,消耗其中一些电池的电量,使得两组电池的使用时长相等。
第三步:两组电池分别装在游戏机的两个电池位置上,运行游戏机。

已知有n个电池,将其电池分为两组,第1组时长加和为 a a a,第2组时长加和为 b b b
不失一般性,假设最后第1组使用时长大于等于第二组,即 a ≥ b a\ge b ab。其差值 d = a − b d = a-b d=ab
定义消耗操作:在某一组电池中取出一对电池使用,游戏机运行 m 2 \frac{m}{2} 2m时长,共消耗电池使用时长 m m m

贪心选择:按使用时长从大到小选择电池,将其加入电池使用时长加和更小的分组中。
在所有电池都分配结束后

  1. 如果使用时长更长的第1组中只有1个电池,其它所有电池都在第2组。那么这也就是最优的方案了,此时游戏机可以运行的时长为 b b b,即为电池中除了使用时长最长的电池,其余电池使用时长的加和。

  2. 只要第1组中的电池数量大于1,那么一定可以通过1次消耗操作让第1组的电池消耗掉使用时长 d d d,进而让两组电池的使用时长加和相同。
    证明:

    在第1组最后一节电池加入时,一定是第1组的使用时长加和 a 1 a_1 a1小于等于第2组的加和 b 1 b_1 b1,即 a 1 ≤ b 1 a_1\le b_1 a1b1。而后第1组加入最后一节电池,其时长为 a e a_e ae,此时第1组电池使用时长 a = a 1 + a e a = a_1+a_e a=a1+ae,其后第2组加入了0节或多节电池,这些电池的总时长为 b e b_e be,最后第2组电池的使用时长 b = b 1 + b e b = b_1 + b_e b=b1+be
    那么两组电池使用时长的差值 d = a − b = a 1 + a e − b 1 − b e = a e − ( b 1 − a 1 ) − b e d = a - b = a_1+a_e - b_1 - b_e = a_e - (b_1-a_1) - b_e d=ab=a1+aeb1be=ae(b1a1)be,由于 b 1 − a 1 ≥ 0 b_1-a_1\ge 0 b1a10 b e ≥ 0 b_e \ge 0 be0,所以 d ≤ a e d \le a_e dae
    由于第1组中不只有1节电池,根据贪心选择,其中已经存在的电池的时长一定大于等于后面加入的电池的时长。所以第1组中除了最后一节电池,一定存在时长为 a m a_m am的某电池满足 a m ≥ a e a_m \ge a_e amae,取出这两节电池放入游戏机中运行,运行时长 d 2 \frac{d}{2} 2d,共消耗时长 d d d。由于 d 2 ≤ d ≤ a e ≤ a m \frac{d}{2} \le d \le a_e \le a_m 2ddaeam,所以一定可以做到运行这么久。
    此时第1组电池的剩余总运行时长为 a − d = b a - d = b ad=b,与第2组电池的总运行时长相同。分别取第1组和第2组的电池放在游戏机的两个电池空位上,运行游戏机,还可以运行 b b b时长。

    这种方案下,电池电量没有一点浪费,游戏机可以运行的总时长为所有电池可以使用的总时长除以2。

2. 具体做法

将输入的数据存入数组,求其中的最大值及所有数的总和。总和减最大值为剩余数字和。
如果最大值大于等于剩余数字和,那么结果为剩余数字和。否则,输出总和除以2。

【题解代码】

解法1:贪心
#include<bits/stdc++.h>
using namespace std;
#define N 1005
int main()
{
    double a, ans;
    int n;
    while(cin >> n)
    {
        double mx = 0, sum = 0;
        for(int i = 1; i <= n; ++i)
        {
            cin >> a;
            mx = max(mx, a);
            sum += a;
        }
        if(sum - mx < mx)
            ans = sum - mx;
        else
            ans = sum / 2;
        cout << fixed << setprecision(1) << ans << endl;
    }       
    return 0;
}
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值