洛谷1315 觀光公交(貪心)
阿新 • • 發佈:2018-11-10
題目
風景迷人的小城Y市,擁有n個美麗的景點。由於慕名而來的遊客越來越多,Y市特意安排了一輛觀光公交車,為遊客提供更便捷的交通服務。觀光公交車在第0分鐘出現在1號景點,隨後依次前往2、3、4……n號景點。從第i號景點開到第i+1號景點需要Di分鐘。任意時刻,公交車只能往前開,或在景點處等待。
設共有m個遊客,每位遊客需要乘車1次從一個景點到達另一個景點,第i位遊客在Ti分鐘來到景點Ai,希望乘車前往景點Bi(Ai<Bi)。為了使所有乘客都能順利到達目的地,公交車在每站都必須等待需要從該景點出發的所有乘客都上車後才能出發開往下一景點。假設乘客上下車不需要時間。
一個乘客的旅行時間,等於他到達目的地的時刻減去他來到出發地的時刻。因為只有一輛觀光車,有時候還要停下來等其他乘客,乘客們紛紛抱怨旅行時間太長了。於是聰明的司機ZZ給公交車安裝了k個氮氣加速器,每使用一個加速器,可以使其中一個Di減1。對於同一個Di可以重複使用加速器,但是必須保證使用後Di大於等於0。
那麼ZZ該如何安排使用加速器,才能使所有乘客的旅行時間總和最小?
題解
貪心
設arr[i]表示公交到i的時間,lat[i]表示公交離開i的最早時間,tot[i]表示1~i中上車的人(字首和)。
貪心的想,每次選擇一段人最多的使用氮氣加速是最優的,我們甚至可以直接把某條路的D縮成0為止。
對於一段[i,wei]使用一次氮氣可以提速tot[wei]-tot[i],前提是提速後有arr<=lat[i]。
程式碼
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int inf=1<<30; const int maxn=1010,maxm=10010; int n,m,k,ans=0; int d[maxn]; int arr[maxn],lat[maxn],tot[maxn]; struct U{int t,x,y;}a[maxm]; bool solve() { int wei=n,now_k=inf; int best_i,best_tot=0,best_k=inf,best_wei; for(int i=n-1;i>=1;i--)//i~i+1 { if(arr[i+1]<=lat[i+1])//debug arr[i]<=lat[i] { wei=i+1; now_k=arr[i+1];//now_k記錄最大減少的k } else now_k=min(now_k,arr[i+1]-lat[i+1]); if(d[i] && best_tot<tot[wei]-tot[i]) { best_tot=tot[wei]-tot[i]; best_i=i; best_wei=wei; best_k=min(now_k,min(k,d[i])); } } if(best_k==0) return false; k-=best_k; ans-=best_k*best_tot; d[best_i]-=best_k; for(int i=best_i+1;i<=best_wei;i++) arr[i]-=best_k;//debug best_i+1 return true; } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<n;i++) scanf("%d",&d[i]); for(int i=1;i<=m;i++) { scanf("%d%d%d",&a[i].t,&a[i].x,&a[i].y); lat[a[i].x]=max(lat[a[i].x],a[i].t); tot[a[i].y]++; } arr[1]=0; for(int i=2;i<=n;i++) { tot[i]+=tot[i-1]; arr[i]=max(arr[i-1],lat[i-1])+d[i-1]; } for(int i=1;i<=m;i++) ans+=arr[a[i].y]-a[i].t; while(solve()); printf("%d\n",ans); return 0; }