1551: A
Time Limit: 1 Sec Memory Limit: 128 MB[Submit][Status][Web Board]
Description
给出一个n*m的矩阵,矩阵由组成Aij(0=<i<n,0=<j<m,-100<=Aij<=100),现在从A00出发,可以向右走,向上走,向下走但不能向左走,并且每个位置只能走过一次,问怎么走到达An-1m-1使经过的所有点的和最大
Input
输入一个整数T,表示有T组数据
输入两个正整数n,m表示矩阵为n*m的矩阵
输入n行m列表示矩阵上的每个点的数值(-100~100)
Output
每个案例输出从(0,0)点出发到达(n-1,m-1)点的路径上每个点的和的最大值
Sample Input
1
3 3
1 2 3
4 5 6
7 8 9
Sample Output
45
【分析】
dp...状态转移挺复杂的...改了半天...发现自己考虑不够全面...
状态转移的方向题目里已经说的很清楚了,上下左三个方向,那么定义f[i][j][k]表示到达坐标(i,j)时从k方向过来的最大值。
/0上 1下 2左
因为不能这道题的状态转移显然是竖着来的,所以for (j) for (i)的顺序,竖着遍历
然后在状态转移上也必须要有顺序,那就是必须先转移f[i][j][2]
因为在当前j列,0和1的状态转移都可以被2影响,所以要先把2的状态转移做完,然后考虑0和1,因为不能重复走,所以
f[i][j][0]只能从f[i-1][j][0/2]转移
f[i][j][1]只能从f[i+1][j][1/2]转移
并且显然的,我们这里的遍历是i,那么就需要考虑这两个情况能否影响下面的情况?
答案是当然的,显然在第j列,我们可以一直向上走,或一直向下走,所以对于0的状态我们要正向,一直向下,对于1的状态我们要反向,也就是一直向上~状态转移的影响想清楚就好了...
我一开始想的不是很清楚...以为f[i][j][0]和f[i][j][1]都可以正向遍历....改了好久才发现问题0.0果然还是自己太菜
【代码】
#include <stdio.h>
#include <algorithm>
using namespace std;
int f[110][110][4];
// 0 up
// 1 down
// 2 left
int a[150][150];
int main()
{
int pp;scanf("%d",&pp);
while (pp--)
{
int n,m;scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
for (int i=0;i<=n+1;i++)
for (int j=0;j<=m+1;j++)
for (int k=0;k<3;k++)
f[i][j][k]=-100000000;
f[0][1][0]=f[0][1][1]=f[0][1][2]=0;
for (int j=1;j<=m;j++)
{
for (int i=1;i<=n;i++)
f[i][j][2]=max(max(f[i][j-1][0],f[i][j-1][1]),f[i][j-1][2])+a[i][j];
for (int i=1;i<=n;i++)
f[i][j][0]=max(f[i-1][j][0],f[i-1][j][2])+a[i][j];
for (int i=n;i;i--)
f[i][j][1]=max(f[i+1][j][1],f[i+1][j][2])+a[i][j];
}
printf("%d\n",max(max(f[n][m][0],f[n][m][1]),f[n][m][2]));
}
}