poj 1700 Crossing River 过河问题

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





ps:

算法思想:

假设有n个人,编号为0,1,2,……,n-1,每个人的过河时间为a[i],且a[i]<a[i+1](i=0,1,2,……,n-1)

可发现,该过桥的过程为一个迭代的过程,若用f(n)来表示最优解,那么当有k个人用时s(k)过桥后,并且手电筒又重新回到原来的一边时,f(n)=f(n-k)+s(k)

此外,每次过河时,应该过两个人,而送手电筒过河时,应该只过一个人

可发现,被浪费的时间花费总是在送手电筒的过程中,因此应当使这份时间最少,因而送手电筒的任务应该交给过桥时间最短的人来做,

若这个任务只交给0号来做,那么会出现一个问题,就是当另外一个人的过河时间a[t]远大于a[0],则不划算,只是浪费时间

如n=4, a={1,2,6,7}时,

最优的顺序应为,先让1、2过河,1回来,然后6、7过河,然后2回来,最后1、2过河,用时2+1+7+2+2=14

可见,只让一个人送手电筒的方法不可取,因为一个较慢的人和另一个和他时间接近的人同时过河,可同时送两个较慢人过河,且费时相同。

到此可发现,因为最多一次过河两个人,因此可取k=2(此题可扩展为每次可过河n个人,此时k应取n),让0号和1号来送手电筒,那么剩下的就是s(k)的计算了。

假设0号和1号送k-1号和k号过河,则s(2)的计算方法如下:

一种为上述所示,0、1过河,然后0回,k-1、k过河,然后1过河,此时  f(n)=f(n-2) + a[1] + a[0] + a[k] + a[1]

另一种为0、k-1过河,0回,0、k过河,0回,f(n)=a[k-1] + a[0] + a[k] + a[0]

综上所述,

s(2)=a[0] + [k] + min( 2*a[1], a[0]+a[n-1] )

代码:

#include<stdio.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
int minn(int a,int b)
{
    return a<b?a:b;
}
int main()
{
    int t,t1,t2,n,a[1020];
    scanf("%d",&t);
    while(t--)
    {
        int sum=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        sort(a,a+n);
        while(n>=4)
        {

            t1=a[0]+a[1]*2+a[n-1];
            t2=a[n-1]+a[n-2]+a[0]*2;
            sum+=minn(t1,t2);
       //printf("%d###\n",sum);
            n-=2;
        }
           if(n==3)
            sum+=a[0]+a[1]+a[2];
            else if(n==2)
                sum+=a[1];
            else if(n==1)
                sum+=a[0];
        printf("%d\n",sum);
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值