今天开始研究DP,今天是4.10 离省赛开始还有25天。
先来说一下这个题,一开始把题意看错了,没有看到必须在一个位置相遇。菜啊
这个题一开始想到了将问题转化成计算从相遇点到起点和终点的距离。
但是还是不知道怎么划分状态,看完题解后,想到了一个点就是”累积性”。联想到了概率上的分布函数,可能这就是“递推的本质”。
说一下这个题的思路。
先来说一下为什么将问题转化成相遇点到各个角的最大价值。
首先因为题目的要求必须有一个相遇点,这个很关键,一开始没翻译出来.然后假设有这样的一个点,然后可以画出几个简单的情景,或者想一下就会发现,如果只有一个相遇点的话,就会有两种情况,假设A是向左进入相遇点的话,必须从左边出相遇点,如果换方向的话,就会有另外的相遇点。
这样的话出现上面的情况,这样的话,就可以转化成各个角到相遇点的最大价值,现在就是打表算出从各个角出发到所有点的最大价值.
然后枚举所有可能的相遇点.
就可以了
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int MAXN = 1e3 + 10;
LL dp[MAXN][MAXN][4]; // 四个方向
LL a[MAXN][MAXN];
void f(int n,int m)
{
memset(dp,0,sizeof(dp));
for(int i = 1;i <= n; ++i)
{
for(int j = 1;j <= m;++j)
{
dp[i][j][0] = max(dp[i - 1][j][0],dp[i][j - 1][0]) + a[i][j];
}
}
for(int i = n;i >= 1;--i)
{
for(int j = 1; j <= m;++j)
{
dp[i][j][1] = max(dp[i + 1][j][1],dp[i][j - 1][1]) + a[i][j];
}
}
for(int i = n;i >= 1;--i)
{
for(int j = m;j >= 1;--j)
{
dp[i][j][2] = max(dp[i + 1][j][2],dp[i][j + 1][2]) + a[i][j];
}
}
for(int i = 1;i <= n;++i)
{
for(int j = m;j >= 1;--j)
{
dp[i][j][3] = max(dp[i - 1][j][3],dp[i][j + 1][3]) + a[i][j];
}
}
}
int main()
{
ios::sync_with_stdio(false);
int n,m;
while(cin >> n >> m)
{
for(int i = 1; i <= n;i++)
{
for(int j = 1;j <= m;++j)
cin >> a[i][j];
}
f(n,m);
LL ans = 0;
for(int i = 2; i <= n - 1; ++i)
{
for(int j = 2;j <= m - 1;++j)
{
ans = max(ans,dp[i - 1][j][0] + dp[i + 1][j][2] + dp[i][j - 1][1] + dp[i][j + 1][3]);
ans = max(ans,dp[i - 1][j][3] + dp[i + 1][j][1] + dp[i][j - 1][0] + dp[i][j + 1][2]);
}
}
cout << ans << endl;
}
return 0;
}
总 结 一 下 : 就是递推的就是 "累积“和”状态的选择和转化“