日常刷题2025-3-7
日常刷题2025-3-7
收集金币
正解:路径DP
如果没有变成墙壁的条件,就是很经典的一道入门DP,公式 \(dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]) + val[i][j]\)。 由于只能向右和下移动,记左上角坐标 \((1,1)\),那么到达点 \((i, j)\) 的回合一定是 \(i - 1 + j - 1\)。如果变成墙壁是在这个回合及之后,那么就可以直接通过,反之点权赋极小值即可。
评述
想到了DP,不过卡在了时间复杂度上,甚至还想了一个bfs的算法,可惜被卡。有时候需要相信自己的直觉,DP做不出来有可能是因为题目还没有理解透彻。
代码
#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int n, m;
std::cin >> n >> m;
std::vector tag(n+1, std::vector<int>(m+1, 1e9));
std::vector d(n+1, std::vector<int>(m+1));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
std::cin >> d[i][j];
int t; std::cin >> t;
for (int i = 0; i < t; i++) {
int x, y, v; std::cin >> x >> y >> v;
tag[x][y] = v;
}
std::vector dp(n+1, std::vector<i64>(m+1, -1e9));
dp[1][1] = d[1][1];
// dp[0][1] = 0;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (i + j - 2 >= tag[i][j]) d[i][j] = -1e9;
}
}
i64 ans = d[1][1];
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (i == 1 && j == 1) continue;
dp[i][j] = std::max(dp[i-1][j], dp[i][j-1])+d[i][j];
ans = std::max(ans, dp[i][j]);
}
}
std::cout << ans << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

浙公网安备 33010602011771号