洛谷 - P1009 - 传纸条(多维DP)

题目链接 : https://www.luogu.com.cn/problem/P1006

想到了用四维数组来枚举的,但是不太明白如何判重。后来才明白,只需要令 x2 > x1 即可

先来分析状态转移方程 :

dp[ x1 ][ y1 ][ x2 ][ y2 ]   = max(   max( dp[ x1 + 1 ][ y1 ][ x2+1 ][ y2 ] , dp[ x1 ][ y1+1 ][ x2 ][ y2+1 ]   )

                                               max( dp[ x1+1 ][ y1 ][ x2 ][ y2+1 ] , dp[ x1 ][ y1+1 ][ x2+1 ][ y2 ]     )

                                            )   + board[ x1 ][ y1 ] + board[ x2 ][ y2 ]

它表示,对于某一个时刻, A在位置 ( x1,y1 ) , B在位置( x2,y2 ),它可以由4种途径得到:分别为 A的两种方式到达 (x1,y1) 和 B的两种方式到达( x2,y2 )的四种组合。最后加上新得到的分数

 

接下来还剩下三个问题:

< 1 > dp初值条件:这个好说,就是 0。(补充一点:题目要求来回传纸条,等价于一个人传给另一个人两张纸条。这样可以方便的固定dp起点 )

< 2 > dp的循环顺序:由于是从 右下角的(x,y) 走到左上角的(1,1) , 每一个靠左上方的点的状态,都需要由靠右方、下方的点的状态推得,故变量由 x -> 1,  y -> 1,表示从右下向左上推导。

< 3 > dp终点?由于我们控制了 x2 > x1 , 故最终不可能得到 dp[1][1][1][1]的状态,而应该是即将变为dp[1][1][1][1]的状态,也就是 -->  dp[2][1][1][2]

另外:

四层嵌套for循环的合理性?

首先在避免重复的这一点上肯定是合理的(限制了x2 > x1)

现在只需要考虑: 为什么这样的循环顺序,即现枚举x1的一个状态,再枚举所有的x2状态这种做法合理?

动手画画图可以知道,实际上遍历的顺序是 -> 外两层循环在按照从右到左、从下到上的顺序遍历每一个A的位置 (x1,y1),内两层循环针对每一种(x1,y1)遍历所有 x1 右边的矩形范围内的点(x2,y2)。因此一定可以得到每一种无交点的传递纸条途径。

循环最终得到的x1的最终位置为(1,1),x2的最终位置为(2,1)。但是由于  (x1,y1)为(1,1)时,按照我们的状态方程,它会将 1,2纳入考虑范围内,但是实际上A不可能走到(1,2),否则会与B的路径相交,故最终答案存储在 dp[2][1][1][2] 中。

 

 1 #include <iostream>
 2 #define Maxsize 5
 3 using namespace std;
 4 int board[Maxsize][Maxsize];
 5 int f[Maxsize][Maxsize][Maxsize][Maxsize];
 6     //   x1      y1       x2       y2
 7 int main(){
 8     int x,y;
 9     cin >> x >> y;
10     for(int i = 1; i <= x; i++){
11         for(int j = 1; j <= y; j++){
12             cin >> board[i][j];
13         }
14     }
15     for(int x1 = x; x1 >= 1; x1--)
16         for(int y1 = y; y1 >= 1; y1--)
17             for(int x2 = x1 + 1; x2 >= 1; x2--)
18                 for(int y2 = y; y2 > y1; y2--){
19                     f[x1][y1][x2][y2] = max(
20                         max( f[x1+1][y1][x2+1][y2] , f[x1][y1+1][x2][y2+1] ),
21                         max( f[x1+1][y1][x2][y2+1] , f[x1][y1+1][x2+1][y2] )
22                                         )
23                     + board[x1][y1] + board[x2][y2];
24                 }
25     cout<<f[1][1][1][2];
26     cout<<f[2][1][1][2];
27     return 0;
28 }
posted @ 2020-01-03 14:56  popozyl  阅读(196)  评论(0编辑  收藏  举报