題目大意是一個機器人從1.1出發,要到達m.n點,去的時候只能往右或往上走,回來的時候只能往上或往左走,但是一個點只能走一次,沿途每個點均有寶藏,問最多能拿回寶物的價值是多少。
此問題等價於從1.1出發兩個機器人,均要到達m.n點,設兩個機器人的速度是一定的,則每一個時刻兩個機器人均不能走到相同的格子內,(除了到達m.n的時候)。
若想去的兩個機器人不走到同一點,則只需要任意時刻,機器人1所在的行數不等於機器人2所在的行數。因為速度相同,出發點相同,若某一時刻k時兩個機器人到達了同一行,則他們的列數也必然會相同,所以只需要不在同一行即可,
設f[k][i][j]為第k步時1號機器人在i行2號機器人走到j行所收集的最大寶物價值,則f[k][i][j]=max(f[k-1][i-1][j],f[k-1][i][j-1],f[k-1][i][j],f[k-1][i-1][j-1])+a[i][k+2-i]+a[j][k+2-j];
如果設1號機器人走的是左邊的路線,2號機器人走的是右邊的路線,由於路線不想交,所以1號機器人第一步是往下的,而2號機器人是往右的,而到達終點前1號機器人不會達到第n列,同樣2號機器人不會到達第m行,然後i和j的取值范圍要考慮,必須使得兩個的行數均在(1,m)之間,列數均在(1,n)之間,而如果k+1<m時,行數均是小於m的,
我們同樣可以這樣考慮,由於機器人每前進一步,行數和列數有且僅有一個將增加1,所以我們可以考慮k的值代表行數和列數的和,則樣比較容易理解,由於到達終點的時候,兩條線路必須相交,所以我們可以不讓到達終點,即k<m+n;狀態轉移方程就變成了f[k][i][j]=max(f[k-1][i-1][j],f[k-1][i][j-1],f[k-1][i][j],f[k-1][i-1][j-1])+a[i][k-i]+a[j][k-j];(k>=3&&k<m+n);
參考代碼如下;
[cpp]
#include <iostream>
#include <cstring>
#define MAX_SIZE 51
using namespace std;
int f[2*MAX_SIZE+10][MAX_SIZE+10][MAX_SIZE+10];
int a[MAX_SIZE+10][MAX_SIZE+10];
int m,n;
int max(int a,int b)
{
if(a>b)
return a;
return b;
}
void execute()
{
if(m==1||n==1)
{
cout<<0<<endl;
return ;
}
memset(f,0x80,sizeof(f));
int k,i,j;
f[2][1][1]=0;
for(k=3;k<m+n;k++)
{
for(i=2;i<k&&i<=m;i++)
{
if(k-i>=n||k-i<1)
continue;
for(j=1;j<k-1&&j<=m-1;j++)
{
if(i==j)
continue;
if(k-j>n||k-j<=1)
continue;
f[k][i][j]=max(max(f[k-1][i-1][j],f[k-1][i-1][j-1]),max(f[k-1][i][j-1],f[k-1][i][j]));
f[k][i][j]=f[k][i][j]+a[i][k-i]+a[j][k-j];
}
}
}
int ans=f[m+n-1][m][m-1]+a[m][n];
cout<<ans<<endl;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>m>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
execute();
}
return 0;
}
#include <iostream>
#include <cstring>
#define MAX_SIZE 51
using namespace std;
int f[2*MAX_SIZE+10][MAX_SIZE+10][MAX_SIZE+10];
int a[MAX_SIZE+10][MAX_SIZE+10];
int m,n;
int max(int a,int b)
{
if(a>b)
return a;
return b;
}
void execute()
{
if(m==1||n==1)
{
cout<<0<<endl;
return ;
}
memset(f,0x80,sizeof(f));
int k,i,j;
f[2][1][1]=0;
for(k=3;k<m+n;k++)
{
for(i=2;i<k&&i<=m;i++)
{
if(k-i>=n||k-i<1)
continue;
for(j=1;j<k-1&&j<=m-1;j++)
{
if(i==j)
continue;
if(k-j>n||k-j<=1)
continue;
f[k][i][j]=max(max(f[k-1][i-1][j],f[k-1][i-1][j-1]),max(f[k-1][i][j-1],f[k-1][i][j]));
f[k][i][j]=f[k][i][j]+a[i][k-i]+a[j][k-j];
}
}
}
int ans=f[m+n-1][m][m-1]+a[m][n];
cout<<ans<<endl;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>m>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
execute();
}
return 0;
}