1. 程式人生 > >NYOJ 47 過河問題 (貪心)

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

分析:

如果n==1或者n==2,所有人直接過河即可;

如果n==3,用時最短的和用時最長的一起過去,然後用時最短的回來,再和剩下的一個人過去 ;

如果n>=4,設a[0]表示用時最短的人所用的時間,a[1]為用時第二短的人所用的時間,a[n-1]表示用時最長的人所用的時間,a[n-2]表示用時第二長的人所用的時間。那麼:

當2a[1] + a[0] + a[n-1] > 2a[0] + a[n-1] + a[n-2]時,就先讓用時最短的人和用時最長的人一起過去,然後用時最短的回來,接著讓用時最短的和用時第二長的一起過去,再讓用時最短的回來。

否則,就先讓用時最短的和用時第二短的一起過去,然後用時最短的回來,接著讓用時最長和用時第二長的一起過去,再讓用時第二短的回來。這樣就相當於剩下了n-2個人。對這n-2個人執行相同的操作,知道剩下不足4個人即可。

#include<stdio.h>
#include<algorithm>
using namespace std;
int a[1005];
int main()
{
    int T, n, i;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(i = 0; i < n; i++)
            scanf("%d",&a[i]);
        sort(a,a+n);
        int sum = 0;
        while(n >= 4)
        {
            if((a[1] * 2 + a[n-1] + a[0]) > (2 * a[0] + a[n-1] + a[n-2]))
            {  //求出最長的兩個人過橋所用的最短時間
                sum += a[n-1]; //用時最短的和用時最長的一起過去
                sum += a[0]; //用時最短的回來
                sum += a[n-2]; //用時最短的和用時第二長的一起過去
                sum += a[0]; //用時最短的回來
            }
            else
            {
                sum += a[1]; //最短的和第二短的一起過去
                sum += a[0]; //最短的回來
                sum += a[n-1]; //最長的和第二長的一起過去
                sum += a[1]; //第二短的回來
            }
            n -= 2;
        }
        if(n == 3)
            sum += a[1] + a[0] + a[2];
        else if(n == 2)
            sum += a[1];
        else
            sum += a[0];
        printf("%d\n",sum);
    }
    return 0;
}