NYOJ 贪心算法 47 过河问题

过河问题

时间限制:1000 ms  |  内存限制:65535 KB

难度:5

描述

在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,大家是无论如何也不敢过桥去的。不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过。如果各自单独过桥的话,N人所需要的时间已知;而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间。问题是,如何设计一个方案,让这N人尽快过桥。 

输入

第一行是一个整数T(1<=T<=20)表示测试数据的组数
每组测试数据的第一行是一个整数N(1<=N<=1000)表示共有N个人要过河
每组测试数据的第二行是N个整数Si,表示此人过河所需要花时间。(0<Si<=100)

输出

输出所有人都过河需要用的最少时间

样例输入

1
4
1 2 5 10

样例输出

17

首先我来解释一下样例里面的17 是怎么来的。

1)最快的和次快的先过河,最快的回来,时间2+1=3;

2)最慢的和次慢的再过河,次快的回来,时间10+2=12;

3)最快的和次快的最后过河。时间2;

思路分析:(1)我们要尽量减少送手电筒花费的时间,所以要选择过河后较快的人回来。

                    (2)我们要让最慢的和次慢的一起过河,以减少时间的浪费。

                    (3)首先我们设最快为min1,次快为min2,最慢为max1 ,次慢为min2

过河的第一种方法:最快和次快过河,最快回来,最慢和次慢过河,次快回来,最快和次快在过河。

时间为:min2+min1+max1+min2+min2=17

 过河的第二种方法是最快的和最慢的先过河,最快的回来,最快的和次慢的过河,最快的回来,最快的和次快                                 的再过河时间是 max1+min1+max2++min1+min2 =19

很显然在一定条件下第二种方法是优于第一种过河方法的。这里我们先不计算最后两个人过河所学的时间,只计算让最慢和次慢都过河,并且手电筒送回来所花的时间。

当   2*min2>max2+min1 时第二种方案优于第一种方案。时间和为 max1+max2+2*min1(没有计算最后两个人过河所需时间)

当   2*min2<max2+min1 时第一种方案优于第二种方案。时间和为 min1+max1+2*min2(没有计算最后两个人过河所需时间)

知道核心东西之后我们再考虑,在每一组数据中,一定有一个最快的,和次快的,最慢的,和次慢的。我们需要做的就是计算让最慢和次慢都过河并且手电筒送回来后所花的时间。再从剩下没有过河的人中选出最慢的和次慢的,再计算。直到最快的和次快的成为最后两个需要过河的人。如果最后剩下三个人,则过河时间为 三个三个人的过河时间和。

下面上代码:

 
#include <iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
int main(int argc,char* argv[])
{
    int t,n,si[1000],i,sum,min1,min2,max1,max2,l;
    scanf("%d",&t);
    while(t--)
    {   sum=0;
        scanf("%d",&n);
        l=n;
        for(i=0;i<n;i++)
        scanf("%d",&si[i]);
       if(n==1)
        printf("%d\n",si[0]);
       else { sort(si,si+n);
            min1=si[0];
            min2=si[1];

        while(l>0)
        {
            max1=si[l-1];
            max2=si[l-2];
            if(l>3&&(2*min2>max2+min1))
            {
                sum=sum+max1+max2+2*min1;
                l=l-2;
                continue;
            }
            if(l>3&&(2*min2<=max2+min1))
            {
                sum=sum+min1+max1+2*min2;
                l=l-2;
                continue;
            }
            if(l==3)
            {
                sum=sum+si[2]+si[0]+si[1];
                l=l-3;
                continue;
            }
            if(l==2)
            {
                sum=sum+si[1];
                l=l-2;
                continue;
            }
        }
        printf("%d\n",sum);
       }
    }
    return 0;
}
        

猜你喜欢

转载自blog.csdn.net/qq_41661918/article/details/81564854