Codeforces Round 637 (Div. 1)___C. Nastya and Unexpected Guest —— 01bfs

题目链接:点我啊╭(╯^╰)╮

题目大意:

    有 m m m 个休息站,起点为 d 1 d_1 d1,终点为 d m d_m dm
    绿灯时间为 g g g,绿灯时间内必须一直走
    红灯时间为 r r r,禁止走,且红灯时间内必须在休息站
    只有在休息站内可以调整方向,红绿灯交替
    求最短时间

解题思路:

     d p [ i ] [ j ] dp[i][j] dp[i][j] 为到达 i i i 这个休息站,绿灯时间为 j j j,经历了最少的红灯次数
    这样转移的边权只能是 + 1 ( j = = g ) +1(j==g) +1j==g,或者 + 0 ( j < g ) +0(j<g) +0j<g
    就可以用 d e q u e deque deque 维护 01 b f s 01bfs 01bfs 来解决
    边权为 1 1 1 的放在队尾,边权为 0 0 0 的放在队首
    注意不能在结束的时候再计算答案,可能会多计算一次红灯

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 1e4 + 5;
const int maxm = 1e3 + 5;
int n, d[maxn], g, r;
int dp[maxn][maxm];
bool vis[maxn][maxm];
struct node {
	int p, g, r;
};
deque <node> q;
 
void go(node u, int v) {
	if(v < 1 || v > n) return;
	int dis = abs(d[u.p] - d[v]);
	if(u.g + dis > g) return;
	assert(u.r == dp[u.p][u.g]);
	if(u.g + dis == g) {
		if(!vis[v][0]) {
			dp[v][0] = u.r + 1; vis[v][0] = 1;
			q.push_back({v, 0, u.r + 1});
		}
	} else {
		int ng = u.g + dis;
		if(!vis[v][ng]) {
			dp[v][ng] = u.r; vis[v][ng] = 1;
			q.push_front({v, ng, u.r});
		}
	}
}
 
signed main() {
	scanf("%d%d", &n, &n);
	for(int i=1; i<=n; i++) scanf("%d", d+i);
	scanf("%d%d", &g, &r); sort(d+1, d+1+n);
	dp[1][0] = 0; vis[1][0] = 1;
	q.push_front({1, 0, 0});
	ll ans = 1e18;
	while(q.size()) {
		node u = q.front(); q.pop_front();
		if(u.g == 0 && d[n] - d[u.p] <= g) 
			ans = min(ans, 1ll * dp[u.p][u.g] * (g + r) + d[n] - d[u.p]);
		go(u, u.p - 1), go(u, u.p + 1);
	}
	printf("%lld\n", ans == 1e18 ? -1ll : ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值