题目大意
给出一张标有值的方格图,从左上到右下走一次,再往回走一次,使经过的格子中的数之和最大(不允许重复走)
解题思路
容易发现,格子的值不会应为时间发生变化,从左上到右下与从右下到左上完全一样,所以可以将问题变为从左上到右下走两次。
然后就可以注意到这题的题目大意与方格取数一题几乎完全相同,所以我们也用类似的方法处理,枚举两次对应时刻位置的坐标,特判两者位置相等的情况。
我们发现同一时刻所能到达的点总在一条右上到左下的斜线上,所以可以将 4 4 4 重循环压缩成 3 3 3 重循环。
还可以发现,两次走的路一定不会相交,应为相交必然会重复经过同一个格子,而这是不合法的,那么就相当于会有一条路始终在另一条路的下面。据此,我们将枚举第二条路的循环从第一条路下面开始,就可以省去判重。
AC Code
#include <bits/stdc++.h>
//#define int long long
#define For(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
int m,n,a[55][55],f[105][55][55];
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin>>n>>m;For(i,1,n)For(j,1,m)cin>>a[i][j];
//第一维:行走步数;第二维,第一次的当前纵坐标;第三维:第二次的当前纵坐标。
//这里我的第三重循环是从 j+1 开始而不是 1,所以可以省去判在一个格子上的不合法情况。
For(i,2,n+m-2)For(j,1,min(i,n))For(k,j+1,min(i,n))
{
f[i][j][k]=max({f[i-1][j-1][k],f[i-1][j][k-1],f[i-1][j][k],f[i-1][j-1][k-1]})+a[j][i-j+1]+a[k][i-k+1];
}
cout<<f[n+m-2][n-1][n]+f[n+m-2][n][n-1];
return 0;
}
后记
这周也是在有生之年碰到了一次机房停电然,后第二天又有另一个教室停电了,怎么回事呢(