poj1700 crossing river(贪心)

//题意:很好的一道贪心,给一个t代表多组输入,n代表n个人,n个数字代表每个人划到对岸的时间。题目给你一条船,船最多每次载2人也可以一个人,两个人时划船速度为慢的那个人的速度,每次划过到对面后需要一个人在把船划回来接没有过去的人,知道所有人都过去,当然往返都要计时。

//思路:首先想到的是给所有时间排序,每次用划船时间最少的人往返这只是思路之一,这时要考虑的是,如样例所给1 2 5 10;若按照之前思路那肯定是2+1+5+1+10=19;但是我们想如果第一次将1 2 送过去然后1回来,让5 10 过去,让2回来,最后让1 2过去,这样时间是2+1+10+2+2=17,这是另一类思路,也就是每次在让最大的两个过去前先将最小的两个送过去,在返回来一个最小的;这是什么意思呢,也就是我们每次在让人回来接后面的人时肯定用最小的,这一点没有疑问,所以能节省时间的也就是过去的时候,如之前样例所说的样子,这样就发现规律,我们每次判断让最小的送过去还是让当前两个最大自己过去时间少就用那种方式。若用第二种让两个最大过去那么每次都需要再次之前让两个最小的过去再回来一个最小的这样能保证下次回来接人的时候,是尽量小的。

//660k 0ms
#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

int main()
{
    int t, n;
    scanf("%d", &t);
    while(t--){
        //init
        scanf("%d", &n);
        int *cross = new int[n];
        for(int i = 0; i < n; i++){
            scanf("%d", &cross[i]);
        }
        sort(cross, cross+n);
        int sum = 0;

        //thinking
        if(n == 1)
            sum = cross[0];
        else if(n == 2)
            sum = cross[1];
        else if(n == 3)
            sum = cross[0]+cross[1]+cross[2];
        else{
            for(int i = n-1; i > 1; i -= 2){
                if(i >= 3){    //总人数为偶数
                    if(2 * cross[1] <= cross[i-1]+cross[0])    //这里其实是两个思路①②大小的比较,化简后的结果
                        sum += cross[0] + cross[1]*2 + cross[i];//①这里第二小的往返各一次,最小的回来一次,最大的过去一次
                    else
                        sum += 2 * cross[0] + cross[i] + cross[i-1];//②这里最小的要回来两次,两个最大的各过去一次
                }else if(i == 2){    //这里是总人数为奇数
                    sum += (cross[0] + cross[2]);
                }
            }
            sum += cross[1];    //不管人数奇数偶数最后一次必定为两个最小过去那么按照最长时间的
        }
        printf("%d\n", sum);
        delete cross;
    }
    return 0;
}

/*贪心题我觉得一般都很有意思,这种想策略的过程痛苦又快乐,好好琢磨一下*/

猜你喜欢

转载自blog.csdn.net/small__snail__5/article/details/80447850