Crossing River POJ - 1700【贪心问题】

本文探讨了一组人数不等的人如何利用一艘只能容纳两人的小船过河的问题,旨在找到一种策略来最小化所有人过河所需的总时间。文章通过对比两种不同策略的优劣,提出了一种递归算法解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A group of N people wishes to go across a river with only one boat, which can at most carry two persons. Therefore some sort of shuttle arrangement must be arranged in order to row the boat back and forth so that all people may cross. Each person has a different rowing speed; the speed of a couple is determined by the speed of the slower one. Your job is to determine a strategy that minimizes the time for these people to get across.
Input
The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. The first line of each case contains N, and the second line contains N integers giving the time for each people to cross the river. Each case is preceded by a blank line. There won't be more than 1000 people and nobody takes more than 100 seconds to cross.
Output
For each test case, print a line containing the total number of seconds required for all the N people to cross the river.
Sample Input
1
4
1 2 5 10
Sample Output
17

    题目就和曾经在某些数学问题差不多,讲的是:

有N个人想过河,但很不巧他们只有一艘船,然而每次可以过去两个人,但是得派对岸的其中一个人把船再开回来。

讲一下我错误的思路(可能是个通病):

    我一开始想,每次过去两个人,再由一人开船回来,那岂不是每次去一个最快的带上一个河这岸最慢的过去不就可以了吗?但事实并非如此,我们发现这和题目给我们的例子答案不相吻合,得到的是19,显然不正确。

那么接下来讲一个正解,其中也会给出证明:

    当岸这头有许多人的时候,我们得想法设法的尽快把人弄到对岸,如果这次去河对岸的是这些人中最快的两个(耗时分别为a,b),然后再将a送回,把最慢的两个人(耗时分别为x,y(x<y))送到对岸,并由b开船回来——此时的用时是a+2b+y

    按照之前我错误的做法,把两个最慢的人送到河对岸得到的时间为2a+x+y

    那么,我们对两个式子进行比较:2a+x+y>a+2b+y时,a+x>2b那么意味着我之前的思路只在“a+x>2b”这样的条件下才成立,而不成立的时候却符合后面补充的算法。

那么我们可以用个递归解决这类问题:

    当N>=4的时候:

        while(n>=4)
        {
            int t1=2*a[0]+a[n-1]+a[n-2];
            int t2=2*a[1]+a[0]+a[n-1];
            t+=min(t1, t2);
            n-=2;
        }

    接下来处理N<=3就显得简单了:

N==1或者N==2的时候,t+=a[1]。

N==3的时候,就是简单的由最快的人将那两个人分别送过去这么简单了。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <limits>
#include <algorithm>
using namespace std;
int N;
int a[1005];
int t;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        for(int i=0; i<N; i++)
        {
            scanf("%d",&a[i]);
        }
        if(N<=2)
        {
            printf("%d\n",a[N-1]);
            continue;
        }
        t=a[1];
        sort(a, a+N);
        int n=N;
        while(n>=4)
        {
            int t1=2*a[0]+a[n-1]+a[n-2];
            int t2=2*a[1]+a[0]+a[n-1];
            t+=min(t1, t2);
            n-=2;
        }
        if(n==3) t+=(a[2]+a[0]);
        printf("%d\n",t);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值