洛谷P1006 传纸条【dp】

题目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\n", dp[n + m - 1][m][m]);
45     
46     return 0; 
47 }

 

posted @ 2019-05-08 15:36  wyboooo  阅读(106)  评论(0编辑  收藏  举报