补题记录D. Explorer Space

D. Explorer Space

题意:有一个二维的网格图,每两个相邻的格子之间都有一条无向边,问对于每个点来说,走k步的最短路是多少。要求:从\((i, j)\)开始就要从\((i, j)\)结束
方法:DP
其实挺裸的一个dp,但是这里是有一个技巧的,等会说
状态表达:\(dp[i][j][k]\)表示走到\((i, j)\),走了k步的最短路是多少。
状态转移:\(dp[i][j][k] = min(dp[i - 1][j][k - 1] + w_1, dp[i][j - 1][k - 1] + w_ 2, dp[i + 1][j][k - 1] + w_3, dp[i][j + 1][k - 1] + w_4)\)
但是注意题目要求,一定要从哪开始就从哪结束。
我们容易知道,当k是奇数的时候,一定不存在一条走回自己的路。
因为要过去又回来,所以过去回来的路径一定是重复的。所以我们只要求出走\(\frac{k}{2}\)步的最短路,最后答案\(\times 2\)即可
我这个代码主要是建图比较麻烦了。好像有更方便的,我这个就是很普通的建图。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 1e6 + 10;
inline int lc(int u) {return u << 1;}
inline int rc(int u) {return u << 1 | 1;}
inline int lowbit(int x) {return x & (-x);}
LL dp[600][600][30];
int g[600][600];
int h[N], nex[N], val[N], idx;
LL w[N];
inline void add(int a, int b, LL c) {
    val[idx] = b, w[idx] = c, nex[idx] = h[a], h[a] = idx ++ ;
}
inline void solve() {
    memset(h, -1, sizeof h);
    int n, m, kk; cin >> n >> m >> kk;
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) g[i][j] = (i - 1) * m + j;
    }
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j < m; j ++ ) {
            LL x; cin >> x;
            int a = g[i][j], b = g[i][j + 1];
            add(a, b, x), add(b, a, x);
        }
    }
    for (int i = 1; i < n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) {
            LL x; cin >> x;
            int a = g[i][j], b = g[i + 1][j];
            add(a, b, x), add(b, a, x);
        }
    }
    if (kk & 1) {
        for (int i = 1; i <= n; i ++ ) {
            for (int j = 1; j <= m; j ++ ) cout << -1 << ' ';
            cout << endl;
        }
        return ;
    }
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) {
            for (int k = 0; k <= kk; k ++ ) dp[i][j][k] = 1e9 + 7;
        }
    }
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) dp[i][j][0] = 0;
    }
    kk /= 2;
    for (int k = 1; k <= kk; k ++ ) {
        for (int i = 1; i <= n; i ++ ) {
            for (int j = 1; j <= m; j ++ ) {
                int t = g[i][j];
                for (int p = h[t]; ~p; p = nex[p]) {
                    int now = val[p] - 1;
                    int x = now / m + 1, y = now % m + 1;
                    dp[i][j][k] = min(dp[i][j][k], dp[x][y][k - 1] + w[p]);
                }
            }
        }
    }
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) cout << 2ll * dp[i][j][kk] << ' ';
        cout << endl;
    }
}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
//    int t; cin >> t;
//    while (t -- )
    solve();
    return 0;
}
posted @ 2021-04-26 10:41  Time_Limit_Exceeded  阅读(137)  评论(0编辑  收藏  举报