[CF1340C] Nastya and Unexpected Guest - DFS
Description
现在有一条长度为n的街道,你要从0走到n,每个单位时间走一格,每格都有一个红绿灯。你只能朝一个方向并且每个单位时间一定要走一格,但是现在有m个岗亭,你到了岗亭时可以选择是否转向,并且在绿灯最后一秒的时候你一定要在某一个岗亭。问你最少要花多少时间到目的地。(n le 10^6, m le 10^4, g le 10^3)
Solution
我们把一个绿灯周期称为一个阶段,那么我们一定是要先优化阶段数,再优化阶段内的时间
阶段 stage,当前处在的点 p,阶段内的剩余时间 t,我们用 (s,p,t) 来描述一个状态
如果 (i,p,t) 有对应的 (j,p,t) 出现过,满足 (j<i),那么 (i,p,t) 不可能贡献最优解
所以我们分阶段搜索,每段的结束状态扔到后一阶段的起始状态,每段内部做记忆化 DFS
总体复杂度为 O(mg),因为每个状态只会刷一次
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 10005;
const int M = 1005;
int vis[N][M], pos[N], n, m, r, g, ans = 1e18;
vector<int> f[N];
void dfs(int stage, int p, int t)
{
if (p < 1 || p > m)
return;
if (t < 0)
return;
if (vis[p][t])
return;
vis[p][t] = 1;
if (p == m)
ans = min(ans, stage * (g + r) + g - t);
if (t > 0)
{
dfs(stage, p + 1, t - pos[p + 1] + pos[p]);
dfs(stage, p - 1, t - pos[p] + pos[p - 1]);
}
else
{
f[stage + 1].push_back(p);
}
}
signed main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1; i <= m; i++)
cin >> pos[i];
cin >> g >> r;
sort(pos + 1, pos + m + 1);
f[0].push_back(1);
for (int i = 0; i < m; i++)
for (int p : f[i])
dfs(i, p, g);
cout << (ans < 1e16 ? ans : -1) << endl;
}