过河问题

来源:互联网 发布:怎么远程授权php 编辑:程序博客网 时间:2024/04/30 04:26
题目描述 Description
    有一个大晴天,Oliver与同学们一共N人出游,他们走到一条河的东岸边,想要过河到西岸。而东岸
边有一条小船。 
    船太小了,一次只能乘坐两人。每个人都有一个渡河时间T,船划到对岸的时间等于船上渡河时间较
长的人所用时间。 
现在已知N个人的渡河时间T,Oliver想要你告诉他,他们最少要花费多少时间,才能使所有人都过河。 
    注意,只有船在东岸(西岸)的人才能坐上船划到对岸。


输入输出格式 Input/output
输入格式:
输入文件第一行为人数N,以下有N行,每行一个数。 
第i+1行的数为第i个人的渡河时间。
输出格式:
输出文件仅包含一个数,表示所有人都渡过河的最少渡河时间


解析:这道题一开始没什么好的想法。但后来灵机一闪。
    首先我们要进行排序。
    我们用f[i]表示前i个人都过去的情况。很显然,对i的讨论是对i的过河方式的讨论。
    当i是一个人去西岸时,当然是由需时最少的1号把船开回来,把i带到西岸。f[i]=f[i-1]+t[1]+t[i]
    但这显然不一定是最优的。我们会发现,还可以让i和另一个慢的人一起过河,为了不让这两个人
回来,我们当然要先让一个快的去西岸等着。再让一个人把船送回来。显然那两个慢性子就是i和i-1,
把船送回来的当然是1。那1怎么回来呢?当然是2把船送回来,再把1带过去,于是就有:
    f[i]=f[i-2]+f[i]+f[1]+f[2]*2
    两种情况取最佳即可。
    边界:f[1]=t[1]; f[i]=t[2]
    时间复杂度为O(n),满足要求。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;


int t[100001],f[100001];
int main()
{
    int n;
    scanf("%d",&n);
    for (int i=1; i<=n; i++) scanf("%d",&t[i]);
    sort(t+1,t+1+n); //升序排列
    for (int i=1; i<=n; i++) f[i]=0;
    
    f[1]=t[1]; f[2]=t[2];
    for (int i=3; i<=n; i++) f[i]=min(f[i-1]+t[1]+t[i],f[i-2]+t[i]+t[1]+t[2]*2);
    printf("%d",f[n]);
    //system("pause");
    return 0;
}  
    

0 0
原创粉丝点击