AT_abc210_d [ABC210D] National Railway 的题解
洛谷传送门
AT传送门
题目大意
给你一个 n × m n\times m n×m 大小的地点,问你需要选择两个地点建地点站,并在其之间建立轨道,问最小花费。
思路
根据题意,实际上建立轨道的花费相当于是它们的曼哈顿距离 × c \times c ×c,所以如果我们建好了一个站,那么相当于我可以行走到下一个地点再建一个站,所以我们可以先记录好前半部分的最小花费。我们可以用 d p [ i ] [ j ] dp[i][j] dp[i][j] 来表示已经建好了一个地铁站,且已经走到了 ( i , j ) (i,j) (i,j),为了考虑全面,我们遍历的方向实际上就是东北和东南方向。所以我们要分两次来跑,对于东南方向,状态转移方程易知: d p [ i ] [ j ] = { a i j , d p [ i − 1 ] [ j ] + c , d p [ i ] [ j − 1 ] + c } dp[i][j] = \{a_{ij},dp[i-1][j]+c,dp[i][j-1]+c\} dp[i][j]={aij,dp[i−1][j]+c,dp[i][j−1]+c} 那么我们处理好 d p dp dp 数组之后,还有一点就是如何确定最后一个地铁站建在哪最优,哪很明显,我们直接遍历 d p dp dp 数组再枚举我们建立的地铁站即可。
代码
#include <bits/stdc++.h>
#define lowbit(x) x & (-x)
#define endl "\n"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
namespace fastIO {
inline int read() {
register int x = 0, f = 1;
register char c = getchar();
while (c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void write(int x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
}
using namespace fastIO;
const ll INF = 0x3f3f3f3f3f3f3f;
int n, m, c;
ll a[1005][1005], dp[1005][1005], ans[1005][1005];
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n = read(), m = read(), c = read();
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
scanf("%lld", &a[i][j]);
}
}
fill(dp[0], dp[0] + 1005 * 1005, INF);
fill(ans[0], ans[0] + 1005 * 1005, INF);
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
dp[i][j] = min(a[i][j], min(dp[i - 1][j], dp[i][j - 1]) + c);
}
}
ll minn = INF;
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
ans[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + c + a[i][j];
minn = min(ans[i][j], minn);
}
}
for(int i = n; i >= 1; i --) {
for(int j = 1; j <= m; j ++) {
dp[i][j] = min(a[i][j], min(dp[i + 1][j], dp[i][j - 1]) + c);
}
}
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
ans[i][j] = min(dp[i + 1][j], dp[i][j - 1]) + c + a[i][j];
minn = min(ans[i][j], minn);
}
}
printf("%lld\n", minn);
return 0;
}