題意:
現在有一條長度爲n的街道,你要從0走到n,每個單位時間走一格,每格都有一個紅綠燈。你只能朝一個方向並且每個單位時間一定要走一格,但是現在有m個崗亭,你到了崗亭時可以選擇是否轉向,並且在綠燈最後一秒的時候你一定要在某一個崗亭。問你最少要花多少時間到目的地。
題解:
首先這種來回走的問題一般是搜索,那麼我就想到了bfs,但是有一個很重要的點:每兩個崗亭之間的距離是不一樣的,時間間隔不同怎麼能bfs?這時候就要注意這是1維的路,也就是說沒有多種選擇,你每次只能往左邊或者右邊走,所以它可以看成m個點,組成一條鏈,每條邊上都有一個權值,這樣就可以bfs了。
那對於每個點我們需要知道這個點的位置以及到達這裏時花費的綠燈的時間以及到達這裏時花費的總時間。那麼就是三個元素需要二維的數組來維護。
搜索最短路可以選擇spfa或者dijkstra,那麼dijkstra的話需要用優先隊列,這裏怎麼優化掉這個log?可以使用雙端隊列,也就是如果到了紅燈就放到末尾,否則放到前面,也就是將一個整個的綠燈看成權值爲1,否則權值就爲0,那麼在隊首的就是權值最小的了,對於一個綠燈內花了多少時間不用在意。
#include<bits/stdc++.h>
using namespace std;
#define pa pair<int,int>
#define ll long long
const int N=1e4+5,M=1e3+5;
ll dp[N][M],p[N];
int n,m;
ll g_tim,r_tim;
ll bfs(){
ll ans=1e18;
deque<pa>Q;
Q.push_front({1,0});
while(!Q.empty()){
int u=Q.front().first,t=Q.front().second;
Q.pop_front();
if(p[m]-p[u]+t<=g_tim)
ans=min(ans,dp[u][t]+p[m]-p[u]);
int ne=u-1;
if(ne!=0){
int ng=t+p[u]-p[ne];
if(ng>g_tim||~dp[ne][ng%g_tim]);
else{
ll ntim=dp[u][t]+p[u]-p[ne];
if(ng==g_tim)ntim+=r_tim;
dp[ne][ng%g_tim]=ntim;
if(ng==g_tim)
Q.push_back({ne,0});
else
Q.push_front({ne,ng});
}
}
ne=u+1;
if(ne<=m){
int ng=t+p[ne]-p[u];
if(ng>g_tim||~dp[ne][ng%g_tim]);
else{
ll ntim=dp[u][t]+p[ne]-p[u];
if(ng==g_tim)ntim+=r_tim;
dp[ne][ng%g_tim]=ntim;
if(ng==g_tim)
Q.push_back({ne,0});
else
Q.push_front({ne,ng});
}
}
}
if(ans<1e18)
return ans;
return -1;
}
int main()
{
memset(dp,-1,sizeof(dp));
dp[1][0]=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%lld",&p[i]);
sort(p+1,p+1+m);
scanf("%lld%lld",&g_tim,&r_tim);
printf("%lld\n",bfs());
return 0;
}
/*
15 5
0 3 7 14 15
11 11
*/