zoukankan      html  css  js  c++  java
  • 洛谷P3800 Power收集 题解 单调队列优化DP(未完全整理好)

    说明:这篇文章还有很多问题,没有整理好,但是我怕到时候忘了,所以先放上来,等到时候解决了再来更新这篇随笔。

    题目链接:https://www.luogu.com.cn/problem/P3800

    题目大意

    一个 (N imes M) 个二维迷宫,上面有 (K) 个格子上面有宝物,这些宝物有对应的价值,
    你一开始可以选择第一行的任意一个格子进入,然后每次你都会往下走一格,每次往下走一格,你都可以选择在水平方向向左或向右偏移若干个格子,但是最多只能偏移 (T) 个格子。
    你需要寻找一格移动方案,是的从第一行的格子走到第 (N) 行的格子,获得宝物的价值之和最大,输出这个最大价值。

    解题思路

    其实一开始我想到的建图用SPFA求最长路。
    对于第(i)(j) 个宝物,只要 (x_i lt x_j)(|y_i-y_j| ge |x_i-x_j| imes T),则从 (i) 就是可以到达 (j) 的,所以从 (i)(j) 连一条权值为 (v_j) 的边;
    同时,因为所有的点都可能是我第一个到达的点,也都可能是我最后一个到达的点,所以我再设立一个超级源点 (s) 和超级汇点 (t) ,然后从 (s) 向所有的 (i) 连一条权值为 (v_i) 的边,从所有的 (i)(t) 连一条权值为 (0) 的边,然后从 (s)(t) 求最长路。

    然后我因为是用的SPFA求最长路,所以时间复杂度为 (O(V cdot E) = O(K^3)) ,果断超时。

    TLE代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 4040;
    int N, M, K, T, s, t, x[maxn], y[maxn], v[maxn], dist[maxn];
    struct Edge {
        int v, w;
        Edge () {};
        Edge (int _v, int _w) { v = _v; w = _w; }
    };
    vector<Edge> g[maxn];
    queue<int> que;
    bool inq[maxn];
    void spfa() {
        memset(dist, -1, sizeof(dist));
        dist[s] = 0;
        que.push(s);
        while (!que.empty()) {
            int u = que.front();
            que.pop();
            inq[u] = false;
            int sz = g[u].size();
            for (int i = 0; i < sz; i ++) {
                int v = g[u][i].v, w = g[u][i].w;
                if (dist[v] == -1 || dist[v] < dist[u] + w) {
                    dist[v] = dist[u] + w;
                    if (!inq[v]) {
                        inq[v] = true;
                        que.push(v);
                    }
                }
            }
        }
        printf("%d
    ", dist[t]);
    }
    int main() {
        scanf("%d%d%d%d", &N, &M, &K, &T);
        for (int i = 0; i < K; i ++)
            scanf("%d%d%d", x+i, y+i, v+i);
        s = K, t = K+1;
        for (int i = 0; i < K; i ++) {
            g[s].push_back(Edge(i, v[i]));
            g[i].push_back(Edge(t, 0));
        }
        for (int i = 0; i < K; i ++) {
            for (int j = 0; j < K; j ++) {
                if (x[i] < x[j] && abs(y[i] - y[j]) <= T*abs(x[i] - x[j])) {
                    g[i].push_back(Edge(j, v[j]));
                }
            }
        }
        spfa();
        return 0;
    }
    

    然后考虑使用 DP 来解决这个问题。

    定义状态 (v[i][j]) 表示 ((i, j)) 格子的宝物的价值(如果没有宝物则 (v[i][j] = 0)),
    同时定义状态 (f[i][j]) 表示走到 ((i, j)) 能够收获的最大价值,则:

    [f[i][j] = v[i][j] + max_{k in [j-T,j+T]} ( f[i-1][k] ) ]

    而答案就是所有 (f[N][i]) 的最大值。

    然后我们可以用滚动数组优化我们的 (f[N][M]) 的空间为 (f[2][M])

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 4040;
    struct Node {
        int x, y, v;
    } nodes[maxn];
    int N, M, K, T, f[2][maxn], ans;
    bool cmp(Node a, Node b) {
        return a.x < b.x || a.x==b.x && a.y < b.y;
    }
    int main() {
        scanf("%d%d%d%d", &N, &M, &K, &T);
        for (int i = 0; i < K; i ++) scanf("%d%d%d", &nodes[i].x, &nodes[i].y, &nodes[i].v);
        sort(nodes, nodes+K, cmp);
        int c = 0;
        for (int i = 1; i <= N; i ++) {
            for (int j = 1; j <= M; j ++) {
                int v = 0;
                if (nodes[c].x == i && nodes[c].y == j) v = nodes[c++].v;
                if (i == 1) f[i%2][j] = v;
                else {
                    for (int k = max(1, j-T); k <= min(M, j+T); k ++)
                        f[i%2][j] = max(f[i%2][j], f[(i-1)%2][k] + v);
                }
            }
        }
        for (int i = 1; i <= M; i ++) ans = max(ans, f[N%2][i]);
        printf("%d
    ", ans);
        return 0;
    }
    

    但是这样的时间复杂度是 (O(N cdot M cdot K)),所以仍然会超时。

    然后考虑使用 单调队列优化DP

    然后本着不重复造轮子的思想,我要说:我所有的思路都完全来自下面这篇博客:

    https://www.luogu.com.cn/blog/luckyblock/solution-p3800

    按照上述思想,我们能够将时间复杂度优化到 (O(N cdot M))

    实现代码如下:

    
    
  • 相关阅读:
    Key-Value Memory Network
    Deep Mask Memory Network with Semantic Dependency and Context Moment for Aspect Level Sentiment Clas
    Deep Memory Network在Aspect Based Sentiment方向上的应用
    Deep Memory Network 深度记忆网络
    Self Attention 自注意力机制
    Attention基本公式及其变种
    *端策略优化算法(PPO)
    Policy Gradient 算法
    一本通 农场派对
    A
  • 原文地址:https://www.cnblogs.com/quanjun/p/12636587.html
Copyright © 2011-2022 走看看