1 条题解
-
0
这是我第二次打这篇题解……第一次快写完了tm我给关了 双倍经验:NOIP2000方格取数 这道题其实跟那道方格取数一模一样 好了不扯废话我们开始正式讲解 首先,我们的第一个问题就是:怎么简化问题 题目中说纸条要从左上到右下从右下到左上各传一次,并且只能下右走和上左走 那么我们就可以把它看做是两张纸条从左上到右下 那么就满足dp的基本前提:最优化原理和无后效性
由于我不会压维,所以我就不讲了那我们该怎么写状态转移方程? 第一,能不能一遍动规走完再来一遍? 不行,你自己设一套数据就行了 这种做法实质上是披着dp的贪心 你取了两次的最大值相加,但有可能两次都不取最大值相加的和反而更大! 那么我们该怎么写? 让这两张纸条同时开始传! 首先开个四维数组dp[i][j][h][k]表示第一张纸条到(i,j),第二张纸条到(h,k)所取得的最大值,那么dp[n ][m][n][m]即为答案 状态转移方程很好得到:dp[i][j][h][k]=max(max(dp[i-1][j][h-1][k],dp[i][j-1][h][k-1]),max(dp[i-1][j][h][k-1],dp[i][j-1][h-1][k]))+a[i][j]+a[h][k];
你可以尝试着把它与数字金字塔那个一起理解, 其实就是四种情况,第一张和第二张纸条从左边过来大还是从上边过来大 但是(i,j)(h,k)很显然不能重合 那么我们就需要去重:
if(i==h&&j==k) dp[i][j][h][k]-=a[i][j];
既然状态转移方程有了,那么直接用个四重循环枚举就好了 OK解决! 下面完整代码:
#include<bits/stdc++.h> using namespace std; int a[51][51]; int dp[51][51][51][51]; int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { cin>>a[i][j]; } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { for(int h=1;h<=n;h++) { for(int k=1;k<=m;k++) { dp[i][j][h][k]=max(max(dp[i-1][j][h-1][k],dp[i][j-1][h][k-1]),max(dp[i-1][j][h][k-1],dp[i][j-1][h-1][k]))+a[i][j]+a[h][k]; if(i==h&&j==k) dp[i][j][h][k]-=a[i][j]; } } } } cout<<dp[n][m][n][m]; return 0; }
- 1
信息
- ID
- 169
- 时间
- 1000ms
- 内存
- 50MiB
- 难度
- 7
- 标签
- 递交数
- 19
- 已通过
- 9
- 上传者