过河问题(贪心)

过河问题 - 题目详情 - HydroOJ

题目简述:

有n个人一条船,所有人要从左岸渡船到右岸,第i个人过河时间是ai​。船上最多坐两个人,船从右岸回到左岸时必须保证船上有人。每次船的行驶时间等于船上两人中过河时间的较大值
问过河所需最短时间。

输入格式

输入t组数据,每组数据第1行输入n,第2行输入n个数,表示每个人过河的时间。

输出格式

输出t行数据,每行1个数,表示每组过河最少时间。

样例

输入数据 1

1
4
1 2 5 10

输出数据 1

17

 

分析及整体思路

关键在与找到一种普适的最少时间运法,通过样例的启发,比较容易想到我们每回都会从过河时间最少的两者和过河时间最长的两者入手(因为要考虑到每次从右往左回来时还需要有人开船),那么我们先进行整体归纳后发现,当剩余人数为四人及以上时可以一起考虑三人时为一种情况, 两人一人都是一次运完,也可以归纳为一种

对于四人及以上时:

(我们按照过河时间的升序, 把用时最少的两者和用时最多的两者分别编号为t1, t2, t3, t4)

以样例为例, 我们比较容易想到两种思路:

①由于所需时间最长的无论和谁一起都以他的过河时间来计算,所以我们让t4和t3一起过河,而船回来时要借助另外两者,所以我们要先让t1,t2过去, 把t2留在对岸,用来把t3,t4运过去之后把船开回来。那么过程就是:t1,t2一起过去(t2),t1回来(t1),t3,t4过去(t4),t2回来(t2)。此时,t3,t4河左岸所剩人数就-2, 我们继续让t1,t2进行下一轮。

②如若,t2与t1相差时间过大, 那么借助t2运一次就没有一直借助t1来回跑更快, 那么想到另一种方案, 只借助t1,让t1分别把t3,t4运过去:t1,t4过去(t4),t1回来(t1),t1,t3过去(t3),t1回来(t1)。

那么我们在计算四人以上时,只要取这两种方案中时间总和较小者就好

①t2 + t1 + t4 + t2      ②t4 + t1 + t3 + t1

对于三人时:(t1, t2, t3)

经过分析以我们易想到的几种时间较少的过河方案,三者都过去的时间总和都是t1 + t2 + t3

对于两人及一人时:(t1, t2)

由于一趟就可以运完,在代码中这两种情况可以合并,详情见代码

#include <algorithm>
#include <iostream>
using namespace std;
const int N = 1e5 + 10;

signed main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int ans = 0;
        int n;
        cin >> n;
        int a[n];
        for (int i = 0; i < n; i++)
            cin >> a[i];
        sort(a, a + n);
        int ll = 0, rr = n - 1;
        while (rr - ll + 1 >= 4)//四人及以上
        {
            int t1 = ll, t2 = ll + 1, t3 = rr - 1, t4 = rr;
            ans += min(a[t1] + a[t2] * 2 + a[t4], a[t4] + a[t1] * 2 + a[t3]);
            rr -= 2;
        }
        if (rr - ll + 1 == 3)//三人
        {
            ans += a[ll] + a[ll + 1] + a[rr];
        }
        else//两人及一人
        {
            ans += a[rr];
        }
        cout << ans << endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值