两人过桥

来源:互联网 发布:miss淘宝店网址 编辑:程序博客网 时间:2024/04/30 17:12

两人过桥(bridge.???)

问题描述:
有 n 个人希望在晚上通过一座桥。在任何时刻,最多只能有两个人在桥上,并且必须
要带着手电筒才能通过桥。现在的麻烦是只有一个手电筒,所以必须安排某种顺序,使得手
电筒可以被带回去让更多的人过桥(手电筒必须由人带回,不可以从对岸扔过去)。
每个人都有不同的过桥时间,两个人一起过桥所用的时间等于其中较慢的一个。你的
任务是要找出能在最短时间内使所有人都过桥的方案。
输入格式:
第一行是一个整数 n。
接下来有 n 行,每一行给出一个人的过桥时间(整数,单位:秒)。
每个人的过桥时间不超过 100 秒。
输出格式:
输出一行一个数,表示所有人过桥的最短时间。
样例输入:
4
1
2
5
10

样例输出:
17
样例解释:
可以先让 1 和 2 过桥,然后 1 回来,让 5 和 10 过桥,然后 2 再回来带 1 一起过桥,时
间为:2+1+10+2+2=17。
数据限制:
40%的数据满足:n<=100;
100%的数据满足:n<=1000。

分析
贪心法

最简单的一个贪心策略是:让一个最快的人来回带人
但是显然是错误的比如4个人:1 1 100000 100000
最快的来回带的话要:1+1+100000+1+100000=200003
但是如果先将1 1运过去的话,然后1回来,再让100000 100000一起过去
再让右边的1来回一趟,就只要1+1+100000+1+1=100004,这样显然小了

所以第一种贪心的策略显然是不合理的,下面换种贪心策略:
首先,慢的肯定是过了桥之后不回来了
就上面那种情况,我们就是先将最快的两个带过去,
然后快的一个过来,让两个慢的过去,然后让快的再回来,……
但是这种贪心策略也不优,因为:
如果是1 10000 10000 10000,答案又不对了(还是第一种策略优)

结合以上两点,对于最慢的两个人我们有两种处理方法就是:
1、让最快的人来回带
2、让最快的两个人过去,再让最慢的两个一起过去,这样就减少了最慢的重复计算

关于这个贪心策略的证明是:
首先,过桥速度排在第三名之后的人不可能担任送回手电筒的任务,原因是不如速度第一和第二的人送回来得高效。这样,
当前左岸速度最慢的人过桥后就不可能再回来,那么我们可以优先让速度慢的过河,因为其不可能返回,先过后过等效。如此一来,就可以得到上述的贪心策略。

程序:

vara:array[0..12000] of longint;n,i:longint;ans,x,y:int64;procedure kp(l,r:longint);vari,j,mid:longint;begin    if l>=r then exit;    i:=l;j:=r;mid:=a[(i+j) div 2];    repeat         while a[i]<mid do inc(i);         while a[j]>mid do dec(j);         if i<=j then         begin             a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];             inc(i);dec(j);         end;    until i>j;    kp(l,j);    kp(i,r);end;begin    assign(input,'bridge.in');    assign(output,'bridge.out');    reset(input);    rewrite(output);    readln(n);    for i:=1 to n do    read(a[i]);    kp(1,n);    ans:=0;    i:=n;    while true do    begin        if i=2 then ans:=ans+a[2];        if i=3 then ans:=ans+a[1]+a[2]+a[3];        if i<=3 then break;        x:=2*a[2]+a[1]+a[i];        y:=2*a[1]+a[i]+a[i-1];        if x<y then ans:=ans+x else ans:=ans+y;        i:=i-2;    end;    write(ans);    close(input);    close(output);end.
原创粉丝点击