題目大意是只有一艘船,能乘2人,船的運行速度為2人中較慢一人的速度,過去后還需一個人把船划回來,問把n個人運到對岸,最少需要多久。先將所有人過河所需的時間按照升序排序,我們考慮把單獨過河所需要時間最多的兩個旅行者送到對岸去,有兩種方式:
1.最快的和次快的過河,然后最快的將船划回來;次慢的和最慢的過河,然后次快的將船划回來,所需時間為:t[0]+2*t[1]+t[n-1];
2.最快的和最慢的過河,然后最快的將船划回來,最快的和次慢的過河,然后最快的將船划回來,所需時間為:2*t[0]+t[n-2]+t[n-1]。
算一下就知道,除此之外的其它情況用的時間一定更多。每次都運送耗時最長的兩人而不影響其它人,問題具有貪心子結構的性質。即比較t[n-2]+t[0]和2t[1]的大小
下面我們來證明為什么該策略為最優策略:
一.首先證明,先送的應該是最慢的兩個:
1.如果t[n-2]+t[0]-2t[1]<0,那么,就說明,用最小t[0]分別單獨送最慢和次慢的,要優於讓最慢和次慢一起過河。那么這樣,由於其他的t[i]<t[n-2],所以,t[i]+t[0]-2t[1]<t[n-2]+t[0]-2t[1]<0所以讓最小的t[0]分別送所有的人,優於讓他們中的任意兩個人組合一起過河。所以這種情況下過河的總過程可以看成是,判斷最慢的兩個人是否應該一起過河,然后再繼續判斷下一個。
2.如果存在若干個t[i]滿足t[i]+t[0]-2t[1]>0,那么也就是說明,滿足這個條件的這些t[i]都有一個特點,那就是,讓他和任意一個比他大的一起過河,都應該是要優於讓最小的分別送他和那個比他大的過河。那現在,我想要說明的是,對於這些滿足這個條件的t[i],應該讓他們怎么組合,才能得到最優的結果呢:設:x=2t[1]-t[0]。那么,t[0]≤t[1]≤....≤t[i-1]≤x≤t[i]≤...≤t[n].現在,這個x就是一個分界點,x左邊的,讓t[0]分別送最好,x右邊的,任意兩個組合都比這兩個單獨讓t[0]送要快。我假設,讓t[i]和t[n]一起,t[j]和t[n-1]一起,那么他們的時間花費為:t[n]和t[n-1]。而如果我讓t[n-1]和t[n]一起,t[i]和t[j]一起,那么現在該策略的花費為:t[n]+max{t[i],t[j]}≤t[n]+t[n-1]。由此我們的出結論,讓t[n-1]和t[n]在一起一定優於讓他們分別和其他的任意一個組合一起過河。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int t,n,pep[10001],sum; int main() { scanf("%d",&t); while(t--) { memset(pep,0,sizeof(pep)); sum = 0; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&pep[i]); sort(pep,pep+n); while(n > 3) { sum += min( pep[0]*2 + pep[n-1] + pep[n-2] , pep[n-1] + pep[1]*2 + pep[0] ); n -= 2; } if(n == 3) { sum += pep[2] + pep[0] +pep[1]; } if(n == 2) { sum += pep[1]; } if(n == 1) { sum += pep[0]; } printf("%d\n",sum); } return 0; }
