动态规划经典问题:NOIP传纸条问题详解与四维DP实现
一、问题理解与算法选择
传纸条问题要求在一个m×n的矩阵中,从左上角到右下角传递两次纸条(路径不能重复),使得路径上数字之和最大。这个问题可以转化为寻找两条不相交的路径,使它们的和最大。动态规划是解决此类路径优化问题的理想选择,特别是使用四维dp来同时跟踪两条路径的状态。
二、完整代码实现(带详细注释)
#include <iostream> #include <algorithm> using namespACe std; const int MAXN = 55; int grid[MAXN][MAXN]; // 存储每个位置的好心程度 int dp[MAXN][MAXN][MAXN][MAXN]; // 四维DP数组 int main() { int m, n; cin >> m >> n; // 输入矩阵数据 for(int i = 1; i <= m; i++) { for(int j = 1; j <= n; j++) { cin >> grid[i][j]; } } // 动态规划处理 for(int i1 = 1; i1 <= m; i1++) { for(int j1 = 1; j1 <= n; j1++) { for(int i2 = 1; i2 <= m; i2++) { for(int j2 = 1; j2 <= n; j2++) { // 当前最大值来自四种可能的前驱状态 int curr = max( max(dp[i1-1][j1][i2-1][j2], dp[i1-1][j1][i2][j2-1]), max(dp[i1][j1-1][i2-1][j2], dp[i1][j1-1][i2][j2-1]) ); // 如果两条路径走到同一个点,只加一次值 if(i1 == i2 && j1 == j2) { dp[i1][j1][i2][j2] = curr + grid[i1][j1]; } else { dp[i1][j1][i2][j2] = curr + grid[i1][j1] + grid[i2][j2]; } } } } } // 输出结果 cout << dp[m][n][m][n] << endl; return 0; }
三、算法核心解析
状态定义:
dp[i1][j1][i2][j2]表示第一条路径到(i1,j1),第二条路径到(i2,j2)时的最大和
状态转移:
四种可能的前驱状态组合(上上、上左、左上、左左)
使用max函数选择最优前驱
特殊处理:
当两条路径交汇时,只累加一次当前格的值
O(m²n²),适用于m,n≤50的情况
四、优化思路
五、常见问题解答
Q:为什么需要四维DP? A:因为要同时跟踪两条路径的位置,每个路径需要两个坐标。
Q:如何处理路径相交? A:当i1=i2且j1=j2时,只累加一次当前格的值。
Q:能否用DFS解决? A:理论上可以,但时间复杂度太高,不适合较大矩阵。
原创内容 转载请注明出处