1. 程式人生 > >【題解】洛谷P1315 [NOIP2011TG] 觀光公交(字首和+貪心)

【題解】洛谷P1315 [NOIP2011TG] 觀光公交(字首和+貪心)

次元傳送門:洛谷P1315

思路

思路大概想到了 可是程式碼實現卻沒想到 所以參考題解了 D2T3的貪心果然有難度


我們考慮在每次用加速器有兩種情況

  • 到下一個點還需要等待:以後的時間就不再影響了
  • 到下一個點不需要等待:那麼就會影響到後面的時間直到出現情況1(或者到最後一個點)

用sum[i]陣列記錄到i時的總人數 進行字首和處理 e[i]為i可以影響到的最遠的點

那麼sum[i + e[i]] - sum[i] 即是能影響到的人數

這裡需要用到貪心思想 即把影響最大的點用加速器

程式碼

#include<iostream>
#include<algorithm>
using
namespace std; #define maxn 10010 int n,m,k,ans; int need[maxn],tim[maxn],from[maxn],to[maxn],sum[maxn],last[maxn],mintime[maxn],e[maxn]; void fast(int x) { while(x--)//列舉加速器 { e[n]=e[n-1]=n;//每次都初始化影響點 int now,Max=-1;//now為影響最大的點 for(int i=n-2;i>=1;i--)//從後面推回去
{ if(mintime[i+1]<=last[i+1]) e[i]=i+1;//如果要等待 最多影響到下一個 else e[i]=e[i+1];//如果不用等待 就會影響到後面的 } for(int i=1;i<n;i++)//列舉邊 { int temp=sum[e[i]]-sum[i];//列舉影響 if(temp>Max&&need[i]>0)//找出最大影響和位置 並且時間要大於1
{ Max=temp; now=i; } } ans-=Max;//答案減去影響到的人數 need[now]--;//加速的時間減去 for(int i=2;i<=n;i++) mintime[i]=max(mintime[i-1],last[i-1])+need[i-1];//重新計算每個點的最短時間 } } int main() { cin>>n>>m>>k; for(int i=1;i<n;i++) cin>>need[i]; for(int i=1;i<=m;i++) { cin>>tim[i]>>from[i]>>to[i]; last[from[i]]=max(last[from[i]],tim[i]);//此點的最遲時間為每個人從此點出發的最小值 sum[to[i]]++;//在to[i]下車的人數+1 } mintime[1]=last[1];//第一個點初始化 for(int i=1;i<=n;i++) sum[i]+=sum[i-1]; //字首和 for(int i=2;i<=n;i++) mintime[i]=max(mintime[i-1],last[i-1])+need[i-1];//計算到達每個點所需要的最短時間 //最後一個人到前一個站點的時間和到這個點的時間取max for(int i=1;i<=m;i++) ans+=mintime[to[i]]-tim[i];//計算沒有用加速器的答案 後面再減去用加速器的時間 fast(k);//加速辣 cout<<ans; }