1340C.Nastya and Unexpected Guest(最短路+dp+01BFS优化)

题意:

一条路长度为n

从0出发,有m个站点

绿灯红灯交替变换

绿灯的时候必须走

从一个站点出来后方向不能变

红灯的时候必须站在一个站点上

求最短多少时间可以到达n点

题解:

定义(f(i,j))为到第(i)个站点时,绿灯当前时间为(j),经过了最少轮数红绿灯变色

那么(f(i,j))可以往后转移

(f(i-1,j+x)) (f(i+1,j+y)) (f(i,0))

根据题意写转移即可。

这个转移方程要求的是最少轮数,所以就是一个广义的最短路模型。但是这题直接跑(nlogm)的最短路是会被卡掉的。

这里介绍一种基于01图的最短路求解方法,用双端队列代替优先队列做一个01BFS,时间复杂度是(O(n+m))



//定义f(i,j)为到第i个站点时,绿灯当前时间为j,经过了最少轮数红绿灯变色
//那么f(i,j)可以往后转移
//f(i-1,j+x) f(i+1,j+y) f(i-1,0) f(i+1,0)
#include<bits/stdc++.h>
using namespace std;
int n,m,g,r;
int f[10100][1010];
int vis[10100][1010];
int a[10100];
struct qnode {
	int x;
	int y;
	qnode (int xx,int yy) {
		x=xx;
		y=yy;
	}
}; 
long long bfs () {
	deque<qnode> q;
	q.push_back(qnode(0,0));
	vis[0][0]=1;
	long long ans=1e18;
	while (q.size()) {
		qnode tt=q.front();
		q.pop_front();
		if (tt.y==0) {
			//如果当前绿灯时间刚刚开始
			//看看能不能直接走到终点 
			int t1=n-a[tt.x];
			if (t1<=g) {
				long long tmp=1ll*f[tt.x][tt.y]*(g+r)+t1;
				ans=min(ans,tmp);
			}
		}
		if (tt.y==g) {
			if (!vis[tt.x][0]) {
				f[tt.x][0]=f[tt.x][tt.y]+1;
				vis[tt.x][0]=1;
				q.push_back(qnode(tt.x,0));
			} 
			continue;
		}
		if (tt.x>1) {
			//如果不在1号点
			//可以往回走 
			int x=tt.x-1;
			int y=tt.y+a[tt.x]-a[x];
			if (y<=g&&!vis[x][y]) {
				vis[x][y]=1;
				f[x][y]=f[tt.x][tt.y];
				q.push_front(qnode(x,y));
			}
		}
		if (tt.x<m) {
			//如果不在m号点
			//可以往后走
			int x=tt.x+1;
			int y=tt.y+a[x]-a[tt.x];
			if (y<=g&&!vis[x][y]) {
				vis[x][y]=1;
				f[x][y]=f[tt.x][tt.y];
				q.push_front(qnode(x,y));
			}
		}
	}
	if (ans==1e18) ans=-1;
	return ans;
}
int main () {
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++) scanf("%d",a+i);
	scanf("%d%d",&g,&r);
	sort(a+1,a+m+1);
	printf("%lld
",bfs());
}
原文地址:https://www.cnblogs.com/zhanglichen/p/14352751.html