POJ1700 Crossing River

问题链接:POJ1700。

这个问题适合于用贪心法来解决,所以需要对输入的数据事先进行排序。

同时还需要考虑特例情况,数据个数小于3的时候,需要特殊处理;数据个数大于3的时候,需要统一处理。

假设人数为n,总的过河时间为:

n=1时,那个人的过河时间;

n=2时,两人中最长的过河时间;

n=3时,总时间是三人过河时间之和。过河时间最短的人,先送一个过河,再回去和另外一个一起过河。

n>=4时,由过河时间最短的人(一人或两人)带过河时间长的人过河。用贪心法首先将过河时间最长的两个人送过河,以此类推,把所有人都送过河,算出来的时间就是最短过河时间。

假设a,b,c,d四人过河,每人过河的时间大小顺序就是a,b,c,d,并且也用a,b,c,d表示他们的过河时间。那么,送过河时间最长的两个人过河,有两种策略,一是用最快的a送,一个一个带过河,四个人过河总时间为2a+b+c+d;二是用最快的两个人a和b送,先a和b过河并且a回来,再让过河时间最长的两个人c和d一起过河并且b回来,四个人过河总时间为a+3b+d。需要从中选择一个时间最短的方案。

上述贪心法重复的步骤中,送过河时间最长两个人过河时,需要从以上的两个方案中选择一个时间最短的方案。

AC的程序如下:

/* POJ1700 Crossing River */

#include <cstdio>
#include <cstdlib>

int compare(const void*a,const void*b)
{
    return *(int*)a-*(int*)b;
}

int main(void)
{
    int t, n, s[1005], sum, sum1, sum2, i;

    scanf("%d", &t);
    while(t-- > 0) {
        scanf("%d", &n);
        for(i=0; i<n; i++) {
            scanf("%d", &s[i]);
        }

        qsort(s, n, sizeof(int), compare);

        sum = 0;
        while(n > 3) {
            // 每一步将最慢的两个送过河,并且有两种方案可以选择
            
            // 用最快的一个送(最快和最慢四个过河总时间为2*s[0]+s[1]+s[n-2]+s[n-1])
            // 最快的和最慢的先过河,然后最快的一个回来
            sum1 = s[0] + s[n-1];
            // 最快的和次慢的先过河,然后最快的一个回来
            sum1 += s[0] + s[n-2];

            // 用最快的两个送(最快和最慢四个过河总时间为s[0]+3*s[1]+s[n-1])
            // 最快的两个先过河,然后最快的一个回来
            sum2 = s[0] + s[1];
            // 最慢的两个人一起过河,次快的一个回来
            sum2 += s[1] + s[n-1];

            // 上述两个方案中选最小的一个(若2*s[1]>s[0]+s[n-2],则用前一种方案送)
            sum += (sum1 < sum2) ? sum1 : sum2;
            n -= 2;
        }

        if(n==1)
            sum += s[0];
        else if(n==2)
            sum += s[1];
        else if(n==3)
            sum += s[0] + s[1] + s[2];

        printf("%d\n", sum);
    }

    return 0;
}


你可能感兴趣的:(ICPC,river,过河,crossing)