[CF1340C] Nastya and Unexpected Guest

[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;
}


原文地址:https://www.cnblogs.com/mollnn/p/14568785.html