1. 程式人生 > >【貪心策略】渡河(river)

【貪心策略】渡河(river)

例子 整數 inpu tel assign roc con 題目 read

假舟楫者,非能水也,而絕江河。這句話說的是,借助渡船的人,不是會遊水,卻能橫渡江河。

會遊水的人反而不一定能順利地橫渡江河。由於江面風浪很大,他們必須潛泳渡河。這就必須用到氧氣瓶。氧氣瓶當然是出題人買的,而出題人沒錢,所以只買了一個。這種氧氣瓶有兩個輸出氧氣的管道,最多可供兩個人同時過河;其中的氧氣是無限的。

顯然每次應該有兩個人過河,再派對岸的一個人把氧氣瓶送回來。需要註意的是,已經橫渡到對岸的所有隊員都可以送回氧氣瓶。

現在給定你每個人渡河所需的時間,要你求出,按照以上方案把所有人送到對岸,所需的最短時間。兩個人一起過河的時候,所需的時間等於慢的人所用時間。

【輸入文件】第一行,一個正整數

n

其余n個正整數,在第2行,相鄰兩個整數之間用一個空格隔開。

【輸出文件】一行1個整數,表示所用的最短時間。

【樣例輸入】

3

1 3 4

【樣例輸出】8

【數據規模和約定】

對於20%的數據,n<=10

對於100%的數據,文件中的所有整數<=1000

【題解】

本題非常的奇怪,一拿到題目首先想到的貪心方法就是1號做中轉,每次由1號送一個人到對岸,再從對岸送回氧氣瓶。

典型的例子是這組數據: 1 2 9 9

最優的方法是12號過去,1號回來,34號過去,2號回來,12號過去。這個方案花費是16。如果按照原先的方案,花費是22

但是,絕對的存在反例!

典型的例子是這組數據:1 9 9 9

原先的方案最佳(29),新方案反而差(37)

經過仔細觀察,我們發現一個事實,對岸的人只有兩個過河時間最小的人有意義

這裏的意義實質上是由兩個過河時間最小的人來決定最優解。

假定現在我們現在需要挨個過河,有2+2=4個人;

下標 分別是1 2 i-1 i

有兩種方法:

①1號自己把兩個人帶過去。

1 i(1和i共用氧氣筒) 1(1送還氧氣筒) 1 i-1(1把i-1送到對岸) 1(再回來準備下一個)

用時為下標為 i 1 i-1 1的時間之和

1號回來,兩個人一起去對岸,2號回來以後再跟1號一起回去。

1 2(1 2一起去對岸) 1(1回來送氧氣筒) i i-1

(i和i-1自生自滅一起渡河) 2(2回來和1匯合準備下一次)

用時為下標為 2 1 i 2的時間之和

所以記t1=a[1]+a[2]+a[i-1]+a[i];t2=a[2]+a[1]+a[i]+a[2];

sum=sum+min(t1,t2);

接下來分奇偶討論!

當渡河人數為偶數時,偶數-2=偶數

不妨設n恰好為4時,只需要渡河一次,

按照上訴2種方法,①可行,②扯淡,此時②必然會回到本岸,所以還要回去,sum=sum+a[2]

當渡河人數為奇數時,奇數-2=奇數

當n恰好為3時,就是1 2 3的渡河方法,最快的 1 3(1 3去) 1(回來送氧氣筒) 1 2(1 2去)

時間是 3 1 2= a[1]+a[2]+a[3] sum=sum+a[1]+a[2]+a[3];

所以程序就非常簡單:

var t1,t2,n,sum,i:longint;
    a:array[1..1000]of longint;
procedure qsort(l,r:longint);
var t,i,j,mid:longint;
begin
i:=l; j:=r;
mid:=a[(l+r)div 2];
while i<j do
begin
 while a[i]<mid do inc(i);
 while a[j]>mid do dec(j);
 if i<=j then begin
   t:=a[i]; a[i]:=a[j]; a[j]:=t;
   inc(i);dec(j);
 end;
end;
if l<j then qsort(l,j);
if r>i then qsort(i,r);
end;
begin
assign(input,river.in);
assign(output,river.out);
reset(input);
rewrite(output);
 readln(n);
 for i:=1 to n do read(a[i]);
 qsort(1,n);
 if n mod 2=1 then sum:=a[1]+a[2]+a[3]
 else sum:=a[2];
 i:=n;
 while i>3 do begin
 t1:=a[2]+a[1]+a[i]+a[2];
 t2:=a[i]+a[1]+a[i-1]+a[1];
  if t1>t2 then t1:=t2;
  sum:=sum+t1;
  i:=i-2;
 end;
 writeln(sum);
 close(input);
 close(output);
end.

【貪心策略】渡河(river)