题目:https://www.luogu.org/problemnew/show/P1006
题意:
给定一个m*n的矩阵,从(1,1)向下或向右走到(m,n)之后向上或向左走回(1,1),要求路径中每个点都不重复。
问使得权值和最大的路径的权值是多少。
思路:
这道题要学会把问题转化成,找两条从(1,1)到(m, n)互不相交的路径。因为过去和回来其实是相对的。
如果用一个四维dp,dp[i][j][k][l]表示从(1,1)到(i,j)的路径和从(1,1)到(k,l)的路径,他们互不相交的最大权值和。
分别枚举i,j,k,l, dp[i][j][k][l] = max(dp[i][j-1][k-1][l], dp[i-1][j][k-1][l], dp[i-1][j][k][l-1], dp[i][j-1][k][l-1])+g[i][j]+g[k][l]
当(i,j)==(k,l)时,这个点的权值只能算一次。
我们可以发现他走的方向规定之后,代表步数是一定的。因此我们可以缩减一维。
dp[step][i][j]就表示用step步,走到第i行和第j行时的两条互不相交路径的最大权值和。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<map> 4 #include<set> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<cmath> 9 #include<stack> 10 #include<queue> 11 #include<iostream> 12 13 #define inf 0x7fffffff 14 using namespace std; 15 typedef long long LL; 16 typedef pair<string, string> pr; 17 18 int n, m; 19 const int maxn = 55; 20 int heart[maxn][maxn]; 21 int dp[maxn * 2][maxn][maxn]; 22 23 int main() 24 { 25 scanf("%d%d", &m, &n); 26 for(int i = 1; i <= m; i++){ 27 for(int j = 1; j <= n; j++){ 28 scanf("%d", &heart[i][j]); 29 } 30 } 31 32 for(int step = 1; step <= n + m - 1; step++){ 33 for(int i = 1; i <= m; i++){ 34 for(int j = 1; j <= m; j++){ 35 if(step - i + 1 < 1 || step - j + 1 < 1)continue; 36 dp[step][i][j] = max(max(dp[step - 1][i][j], dp[step - 1][i - 1][j]), max(dp[step - 1][i][j - 1], dp[step - 1][i - 1][j - 1])) + heart[i][step - i + 1] + heart[j][step - j + 1]; 37 if(i == j){ 38 dp[step][i][j] -= heart[i][step - i + 1]; 39 } 40 } 41 } 42 } 43 44 printf("%d ", dp[n + m - 1][m][m]); 45 46 return 0; 47 }