题解:AT_abc210_d [ABC210D] National Railway

涉及知识点:动态规划

解题思路

因为 \(W\)\(H\) 的范围都很大,直接枚举两个车站的位置肯定会时间超限的,所以考虑动态规划。

定义 \(dp_{i, j}\) 表示所有横坐标小于等于 \(i\) 且纵坐标小于等于 \(j\) 的点的最小的 \(a_{i', j'} + c\times (i'+j')\) 的值。

非常容易可以得到动态转移方程:

\[dp_{i, j} = \min(dp_{i, j}, a_{i, j} + c\times (i + j)) \]

每个 \(dp_{i, j}\) 的初始值为:

\[dp_{i, j} = \min(dp_{i - 1, j}, dp_{i, j - 1}, dp_{i - 1, j - 1}) \]

答案为:

\[res = \min(res, dp_{i, j} + a_{i, j} + c\times (i + j)) \]

我们发现如果只按照上面的方法做一次动态规划,相当于从矩阵的左上角向右下角转移了一次,并没有考虑到全部情况,还需要从矩阵的右上角向左下角转移一次,相当于把矩阵的每行调转顺序,再按上面的方法转移一次。

最后输出 \(res\) 即可。

小提醒:由于当前点 \((i, j)\) 的值可能会比没有更新的 \(dp_{i,j}\) 的值更优秀,所以需要先初始化 \(dp_{i, j}\),然后更新 \(res\),最后计算 \(dp_{i, j}\)

代码

丑陋的赛时代码。

这里我就只放了核心部分,剩余的部分请读者自己完成。

res = inf;
memset(dp, 0x3f, sizeof dp);
rep(i, 1, n) rep(j, 1, m) {
	dp[i][j] = min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]});
	if (i > 1 || j > 1) res = min(res, dp[i][j] + a[i][j] + c * (i + j));
	if (i > 1 || j > 1) dp[i][j] = min(dp[i][j], a[i][j] - c * (i + j));
	else dp[i][j] = a[i][j] - c * (i + j);
}
memset(dp, 0x3f, sizeof dp);
rep(i, 1, n) reverse(a[i] + 1, a[i] + m + 1);
rep(i, 1, n) rep(j, 1, m) {
	dp[i][j] = min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]});
	if (i > 1 || j > 1) res = min(res, dp[i][j] + a[i][j] + c * (i + j));
	if (i > 1 || j > 1) dp[i][j] = min(dp[i][j], a[i][j] - c * (i + j));
	else dp[i][j] = a[i][j] - c * (i + j);
}
cout << res << endl;
posted @ 2024-10-25 14:42  zla_2012  阅读(4)  评论(0编辑  收藏  举报