补题记录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;
}