CF1340C Nastya and Unexpected Guest(01 BFS)

Description

给定数轴上的 m m 个关键点 { d i } \left\{d_{i}\right\} ,保证其中包含 0 , n 0, n 。需要从 0 0 走到 n n 0 0 时刻开始,在接下来的 g g 个单位时间内必须不停移动,每个单位时间可以移动一个单位距离。如果你现在在两个关键点之间的线段上,你就只能按照上一步行走的 方向继续移动。如果你现在在任意一个关键点上,那么你下一步可以自由选择往左或往右走。当然,你不能移动到 0 的左 边或是 n n 的右边。

g g 个单位时间结束后,你必须恰好在任意一个关键点上, 等待 r r 个单位时间再继续移动。接下来, 在 r r 个单位时间结束后,重新开始 g g 个可以继续移动的单位时间,依此循环。 求按照上述规则,从 0 0 走到 n n 的最短时间。如果无法完成,输出 1 -1

1 n 1 0 6 , 2 m m i n ( n + 1 , 1 0 4 ) , 1 g , r 1000. 1 \leq n \leq 10^6, 2 \leq m \leq min(n + 1, 10^4), 1 \leq g, r \leq 1000.

Solution

d d 从小到大排序,把 g + r g+r 视为一个周期。答案是若干个周期与若干个单位时间之和。在答案的不同周期的同一时间,你都不会在一个相同的点上,否则会构成一个多余的循环。

d i s i , j dis_{i,j} 走到 d i d_i 点,当前周期的绿灯开始了 i i 个单位时间,所需的最小周期数。因为绿灯不能驻足,红灯需在安全点上,所以答案中可能从 d i d_i 走到 d i + 1 d_{i+1} 再走回来。所以要转移相邻的两点。转移考虑的问题有

  • 转移合法,要在绿灯结束前停在关键点上。
  • 走到关键点上,绿灯有没有正好结束,如果结束了那么新增一个周期。

边权只有 0 0 1 1 ,可以 01 BFS。时间复杂度 O ( m g ) O(mg)

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; 
#define mp make_pair
#define pf push_front
#define pb push_back 
#define F first
#define S second
const int N = 1e4 + 5, INF = 0x3f3f3f3f;
inline int read() {
	int x = 0, f = 0; char ch = 0;
	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
	while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
	return f ? -x : x;
}
int n, m, g, r, d[N], dis[N][1000 + 5];
deque <pair <int, int> >q; 
void update(int x, int t, int nx, int nt) {
	if (nt > g) return ; 
	int _nt = (nt == g ? 0 : nt);
	if (dis[nx][_nt] == -1) {
		dis[nx][_nt] = dis[x][t] + (nt == g);
		if (nt < g) q.pf(mp(nx, _nt));
		else q.pb(mp(nx, _nt));
	}
}
signed main() {
	n = read(), m = read();
	for (int i = 1; i <= m; i++) d[i] = read();
	g = read(), r = read();
	sort(d + 1, d + m + 1);
	memset(dis, -1, sizeof(dis));
	dis[1][0] = 0; q.pf(mp(1, 0)); 
	while (!q.empty()) {
		int x = q.front().F, t = q.front().S;
		q.pop_front();
		if (x > 1) update(x, t, x - 1, t + d[x] - d[x - 1]);
		if (x < m) update(x, t, x + 1, t + d[x + 1] - d[x]);
	}
	ll ans = -1;
	for (int i = 0; i < g; i++) 
		if (dis[m][i] !=- 1) {
			ll t = 1ll * dis[m][i] * (g + r) + i - (!i && dis[m][i]) * r;
			if (ans == -1 || t < ans) ans = t;
		}
	printf("%lld\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39984146/article/details/105748650