方格取数
方格取数
设有 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字 。如下图所示:
某人从图中的左上角 出发,可以向下行走,也可以向右行走,直到到达右下角的 点。
在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 )。
此人从 点到 点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。
输入格式
第一行为一个整数 ,表示 的方格图。
接下来的每行有三个整数,第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数。
行和列编号从 开始。
一行“”表示结束。
输出格式
输出一个整数,表示两条路径上取得的最大的和。
数据范围
输入样例:
8 2 3 13 2 6 6 3 5 7 4 4 14 5 2 21 5 6 4 6 3 15 7 2 14 0 0 0
输出样例:
67
解题思路
一开始想到一个贪心的思路,就是两遍dp。第一遍dp得到从到的最大值,然后把走过的格子的值置成,然后继续进行一次dp,得到从到的最大值,两次得到的最大值的和就是答案。但这种贪心做法是错的,因为第一次dp的结果会影响第二次dp的结果,举个反例,一开始格子的值如下:
因此这题应该用dp。由于是两条路径,因此状态应该有维,即表示从走到的第条路径以及从走到的第条路径的集合。根据分别到达和的方向进行状态划分,共种状态,状态转移方程就是
其中
如果有并且,那么应该算一个格子值,即状态转移方程应该只加上而不再加同一个格子的值。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 20; 5 6 int g[N][N], f[N][N][N][N]; 7 8 int main() { 9 int n, a, b, c; 10 scanf("%d", &n); 11 while (scanf("%d %d %d", &a, &b, &c), a || b || c) { 12 g[a][b] = c; 13 } 14 15 for (int i = 1; i <= n; i++) { 16 for (int j = 1; j <= n; j++) { 17 for (int u = 1; u <= n; u++) { 18 for (int v = 1; v <= n; v++) { 19 int w = g[i][j]; 20 if (i != u || j != v) w += g[u][v]; // 不是同一个格子 21 f[i][j][u][v] = max({f[i - 1][j][u - 1][v], f[i - 1][j][u][v - 1], f[i][j - 1][u - 1][v], f[i][j - 1][u][v - 1]}) + w; 22 } 23 } 24 } 25 } 26 27 printf("%d", f[n][n][n][n]); 28 29 return 0; 30 }
可以发现,当的时候,两条路径的格子才可能重合。因此我们可以规定两条路径是同时出发的,这样就可以优化掉一维,得到。其中为两条路径的横纵坐标的和(因为两条路径是同时出发的,因此两条路径的横纵坐标和相同),为第一条路径的横坐标,为第二条路径的横坐标。就得到第一条路径的纵坐标,就得到第二条路径的纵坐标。
如果,说明不是在同一个格子。状态转移方程为
其中
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 30; 5 6 int g[N][N], f[N << 1][N][N]; 7 8 int main() { 9 int n, a, b, c; 10 scanf("%d", &n); 11 while (scanf("%d %d %d", &a, &b, &c), a || b || c) { 12 g[a][b] = c; 13 } 14 15 for (int k = 2; k <= n + n; k++) { 16 for (int i = 1; i <= n; i++) { 17 for (int j = 1; j <= n; j++) { 18 if (k - i < 0 || k - j < 0) continue; // 判断纵坐标是否越界 19 int w = g[i][k - i]; 20 if (i != j) w += g[j][k - j]; // 两个格子不同 21 f[k][i][j] = max({f[k - 1][i - 1][j - 1], f[k - 1][i - 1][j], f[k - 1][i][j - 1], f[k - 1][i][j]}) + w; 22 } 23 } 24 } 25 26 printf("%d", f[n + n][n][n]); 27 28 return 0; 29 }
参考资料
AcWing 1027. 方格取数:https://www.acwing.com/video/354/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16492481.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效