【洛谷3335】【ZJOI2013】蚂蚁寻路

来源:互联网 发布:java去掉括号内容 编辑:程序博客网 时间:2024/06/08 18:15

题目描述

在一个 n*m 的棋盘上,每个格子有一个权值,初始时,在某个格子的顶点处一只面朝北的蚂蚁,我们只知道它的行走路线是如何转弯,却不知道每次转弯前走了多长。蚂蚁转弯是有一定特点的,即它的转弯序列一定是如下的形式:右转,右转,左转,左转,右转,右转…左转,左转,右转,右转,右转。即两次右转和两次左转交替出现的形式,最后两次右转(最后两次一定是右转)后再多加一次右转。我们还知道,蚂蚁不会在同一个位置连续旋转两次,并且蚂蚁行走的路径除了起点以外,不会到达同一个点多次,它最后一定是回到起点然后结束自己的行程,而且蚂蚁只会在棋盘格子的顶点处转弯。

现在已知棋盘大小、每个格子的权值以及左转次数/2 的值,问蚂蚁走出的路径围出的封闭图形,权值之和最大可能是多少。

输入输出格式

输入格式:

在输入文件ant.in 中,第一行三个数n,m,k。意义如题目描述。

接下来一个n 行m 列的整数矩阵,表示棋盘。

输出格式:

一个数,表示蚂蚁所走路径围出的图形可能的最大权值和。

输入输出样例

输入样例#1:
2 5 2-1 -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;}

原创粉丝点击