题目描述
在一个 n*m 的棋盘上,每个格子有一个权值,初始时,在某个格子的顶点处一只面朝北的蚂蚁,我们只知道它的行走路线是如何转弯,却不知道每次转弯前走了多长。蚂蚁转弯是有一定特点的,即它的转弯序列一定是如下的形式:右转,右转,左转,左转,右转,右转…左转,左转,右转,右转,右转。即两次右转和两次左转交替出现的形式,最后两次右转(最后两次一定是右转)后再多加一次右转。我们还知道,蚂蚁不会在同一个位置连续旋转两次,并且蚂蚁行走的路径除了起点以外,不会到达同一个点多次,它最后一定是回到起点然后结束自己的行程,而且蚂蚁只会在棋盘格子的顶点处转弯。
现在已知棋盘大小、每个格子的权值以及左转次数/2 的值,问蚂蚁走出的路径围出的封闭图形,权值之和最大可能是多少。
输入输出格式
输入格式:在输入文件ant.in 中,第一行三个数n,m,k。意义如题目描述。
接下来一个n 行m 列的整数矩阵,表示棋盘。
输出格式:一个数,表示蚂蚁所走路径围出的图形可能的最大权值和。
输入输出样例
2 5 2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
-8
说明
【样例说明】
除了第一行的第二个和第一行的第四个都要围起来才至少合法。
【数据规模与约定】
10%的数据所有格子中权值均非负
另20%的数据n=2
另30%的数据k=0
100%的数据1≤n≤100,1≤m≤100,0≤k≤10 保证存在合法路径,数据有梯度,格子中每个元素的值绝对值不超过 10000
题解
那么自己在草稿纸上画画写写就很容易发现,这题其实是要你在一个n*m大小的矩形中框出一个长城形状的子图,使得子图包含的权值和最大。框出图形的底和左右两边都是直的,上端是一高一低间隔排布,总共有2*k+1个(间隔k次)(如下图)
那么从图中我们可以看出,其实是要求2*k+1个同底的子矩形相连组合起来取得的最大和。
这种题目做的时候很容易往高维度想啊,f[i][j][p][h]表示当前这个子矩形的右下角为(i,j),是第p个矩形,高度为h时取得的最优解。
g[i][j][p][h][0/1]表示当前这个子矩形的右下角为(i,j),是第p个矩形,高度大于等于/小于等于h时的最优解。
得出转移方程:f[i][j][p][h]=max(f[i][j-1][p][h],g[i][j-1][p-1][h][p%2])+s[i][j]-s[h-1][j]
每得出一种转移方式,我们都要想,为什么是这样?
第一个f[i][j-1][p][h]就表示这一列与上一列还在同一个矩形内,变化的只是列+1。
第二个就表示从第j列开始是一个新的矩形。由于矩形是一高一低间隔排布,假设第p个矩形是高的,那么第p-1个矩形肯定要比它低,而高的矩形都是奇数号,所以就是g[i][j][j-1][p-1][h][p%2],低的矩形也同理。
那么g[i][j][p][h][0/1]就在f[i][j][p][h]全更新完后,按照定义的性质从高到低和从低到高分别扫一遍,转移
g[i][j][p][h][0]=max(g[i][j][p][h -1][0],f[i][j][p][h -1])
g[i][j][p][h][1]=max(g[i][j][p][h+1][1],f[i][j][p][h+1])
边界条件为f[i][0][p][h]=g[i][0][p][h][1]=g[i][0][p][h][0]=-inf
最后ans用f[i][j][k][i],g[i][j][k][i][0]来更新。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=210;
const int inf=1000000000;
int n,m,k;
int a[maxn][maxn],s[maxn][maxn],f[maxn][maxn][maxn],g[maxn][maxn][maxn][3],ans=-inf;
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
s[i][j]=s[i-1][j]+a[i][j];
}
k=k*2+1;
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
f[0][i][j]=g[0][i][j][1]=g[0][i][j][0]=-inf;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int p=1;p<=k;p++){
for(int h=i;h>=1;h--)
f[j][p][h]=max(f[j-1][p][h],g[j-1][p-1][h][p%2])+s[i][j]-s[h-1][j];
g[j][p][1][0]=-inf;
for(int h=2;h<=i;h++)
g[j][p][h][0]=max(g[j][p][h-1][0],f[j][p][h-1]);
g[j][p][i][1]=-inf;
for(int h=i-1;h>=1;h--)
g[j][p][h][1]=max(g[j][p][h+1][1],f[j][p][h+1]);
}
ans=max(ans,max(f[j][k][i],g[j][k][i][0]));
}
}
printf("%d\n",ans);
return 0;
}