Codeforces Round #637 (Div. 2)

#include<cstdio>
#include<algorithm>
#include<map>
#include<iostream>
#include<vector>
#include<deque>
using namespace std;
typedef long long ll;
const int N=10010,M=1010;
int n,m;
int g,r;
//定义d[i,j]为到了第i个站点时,绿灯当前时间为j,经过了多少轮红绿灯变换。
int d[N][M];
bool vis[N][M];
int a[N];
struct node
{
	//p表示在那个安全岛
	int p;
	//绿灯经过了多久
	int v;
};
ll bfs()
{
	deque<node>q;
	q.push_back({0,0});
	vis[0][0]=1;
	ll ans=-1;
	while(!q.empty())
	{
		node now=q.front();
		q.pop_front();
		if(now.v==0)//刚等完红灯
		{
			//因为刚等完红灯,所以此时肯定在安全岛
			//在第几个安全岛,还剩下几个点
			int rem=n-a[now.p];
			if(rem<=g)//如果能从这个点直接到终点
			{
				//				几个轮回			走的时间
				ll tmp=1ll*d[now.p][now.v]*(g+r)+rem;
				//更新答案
				if(ans==-1 || tmp<ans)
					ans=tmp;
			}
		}
		//需要灯红灯了
		if(now.v==g)
		{
			//如果当前这个安全岛没有来到过
			if(!vis[now.p][0])
			{
				//次数+1
				d[now.p][0]=d[now.p][now.v]+1;
				//访问过了
				vis[now.p][0]=1;
				//加入丢列
				q.push_back({now.p,0});
			}
			continue;
		}
		//如果安全岛的序号大于1
		if(now.p>1)
		{
			//前一个安全岛的位置
			//也就是往前走
			int p=now.p-1;
			//已经过去的绿灯时间+距离
			int v=now.v+a[now.p]-a[p];
			//如果小于绿灯时间 而且没有走到过
			if(v<=g && !vis[p][v])
			{
				vis[p][v]=1;
				d[p][v]=d[now.p][now.v];
				q.push_front({p,v});
			}
		}
		//如果安全岛的序号小于m
		if(now.p<m)
		{
			//也就是往后走
			int p=now.p+1;
			int v=now.v+a[p]-a[now.p];
			if(v<=g && !vis[p][v])
			{
				vis[p][v]=1;
				d[p][v]=d[now.p][now.v];
				q.push_front({p,v});
			}
		}
	}
	return ans;
}
int main()
{
	cin>>n>>m;
	//安全岛的位置
	for(int i=1; i<=m; i++)
		cin>>a[i];
	cin>>g>>r;
	sort(a+1,a+1+m);
	cout<<bfs()<<endl;
	return 0;
}

原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12790710.html