POJ 1700 & NYLG 47 过河问题(贪心 || DP)

链接 :http://poj.org/problem?id=1700

http://acm.nyist.net/JudgeOnline/problem.php?pid=47

Description

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=1,2,3时所需要的最小时间很容易求得,现在由n>=4,假设n个人单独过河所需要的时间存储在数组t中,将数组t按升序排序,即数组中所表示的时间是递增的.
那么这时将单独过河所需要时间最多的两个旅行者送到对岸去,有两种方式:

    1> 最快的(即所用时间t[0])和次快的过河,然后最快的回来,再次慢的和最慢的过河,然后次快的回来.

    2> 最快的和最慢的过河,然后最快的回来,再最快的和次慢的过河,然后最快的回来.

    这样就将过河所需时间最大的两个人送过了河,而对于剩下的人,采用同样的处理方式,接下来做的就是判断怎样用的时间最少.
    1> 方案1所需时间为:t[0]+2*t[1]+t[n-1];

    2> 方案2所需时间为:2*t[0]+t[n-2]+t[n-1];

    如果方式1优于方式2,那么有:t[0]+2*t[1]+t[n-1]<2*t[0]+t[n-2]+t[n-1] 化简得:2*t[1]<t[0]+t[n-2]
    即此时只需比较2*t[1]与t[0]+t[n-2]的大小关系即可确定最小时间,此时已经将单独过河所需时间最多的两个人送过了河,那么剩下过河的人数为:n-=2,采取同样的处理方式.

(注意:此题的贪心策略是动态的!!!)


代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define MAXN 1000         //最多人数
#define RST(N)memset(N, 0, sizeof(N))
using namespace std;

int s[MAXN];

int cmp(const void *a, const void*b) //按时间从小到大排序
{
    return *(int *)a - *(int *)b;
}

int main()
{
    int cas, n, k, st, a, b;
    scanf("%d", &cas);
    while(cas--) {
        scanf("%d", &n);
        for(int i=0; i<n; ++i) {
            scanf("%d", &s[i]);
        }
        qsort(s, n, sizeof(int), cmp);
        if(n == 1 || n == 2) {
            printf("%d\n", s[n-1]);
            continue;
        }
        st = 0;
        if(n % 2) {            //最后一次过河所需的时间,分为奇数和偶数两种情况
            st+= s[0] + s[1] + s[2];
        }else {
            st+= s[1];
        }
        k = (n - 2) / 2;                       //贪心的次数
        for(int i=0; i<k; ++i) {                  //贪心的策略
            a= s[0] + 2 * s[1] + s[n-1];
            b= 2 * s[0] + s[n-1] + s[n-2];
            if(a < b) {
                st += a;
            }else {
                st += b;
            }
            n -= 2;
        }
        printf("%d\n", st);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值