ABC 210 D - National Railway
D - National Railway
矩阵DP,拆绝对值
设向下为 \(x\) 正方向,向右为 \(y\) 正方向
设两个点为 \((x_1,y_1),\;(x_2,y_2)\), 代价为 \(A_{x_1y_1}+A_{x_2y_2}+|x_1-x_2|+|y_1-y_2|\)
想办法拆掉绝对值
-
\((x_2,y_2)\) 在 \((x_1,y_1)\) 右下方,则 \(|x_1-x_2|+|y_1-y_2|=(x_2+y_2)-(x_1+y_1)\)
\(cost=A_{x_2y_2}+(x_2+y_2)+(A_{x_1y_1}-(x_1+y_1))\)
-
\((x_2,y_2)\) 在 \((x_1,y_1)\) 左下方,则 \(|x_1-x_2|+|y_1-y_2|=(x_2-y_2)-(x_1-y_1)\)
\(cost=A_{x_2y_2}+(x_2-y_2)+(A_{x_1y_1}-(x_1-y_1))\)
在第一种方案中,设 \(f[i][j]\) 以 \((i,j)\) 为右下角的小矩阵中,\(A_{xy}-(x+y)\) 的最小值
\(f[i][j]=min({f[i-1][j],f[i][j-1],A_{ij}-(i+j)})\)
所以枚举 \((i,j)\) 作为 \((x_2,y_2)\), \((x_1,y_1)\) 的最小代价就是 \(f[i][j]\)(注意先更新 \(f[i][j]=min(f[i-1][j],f[i][j-1])\) 后求出当前的答案,再更新 \(f[i][j]=min(f[i][j],A_{ij}-(i+j))\), 因为 \((x_1,y_1)\neq(x_2,y_2)\))
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
#define endl "\n"
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e3 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int n, m;
ll c, a[N][N];
ll f[N][N];
ll solve1()
{
ll ans = INF;
memset(f, 0x3f, sizeof f);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
f[i][j] = min(f[i-1][j], f[i][j-1]);
ans = min(ans, a[i][j] + c * (i + j) + f[i][j]);
f[i][j] = min(f[i][j], a[i][j] - c * (i + j));
}
}
return ans;
}
ll solve2()
{
ll ans = INF;
memset(f, 0x3f, sizeof f);
for (int i = 1; i <= n; i++)
{
for (int j = m; j >= 1; j--)
{
f[i][j] = min(f[i-1][j], f[i][j+1]);
ans = min(ans, a[i][j] + c * (i - j) + f[i][j]);
f[i][j] = min(f[i][j], a[i][j] - c * (i - j));
}
}
return ans;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m >> c;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
ll ans = min(solve1(), solve2());
cout << ans << endl;
return 0;
}