[DP] Jzoj P3198 蚂蚁寻路

Description

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

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

Input

在输入文件ant.in 中,第一行三个数n,m,k。意义如题目描述。
接下来一个n 行m 列的整数矩阵,表示棋盘。

Output

在输出文件ant.out 中,一个数,表示蚂蚁所走路径围出的图形可能的最大权值和。
 

Sample Input

2 5 2
-1 -1 -1 -1 -1
-1 -1 -1 -1 -1

Sample Output

-8
 

Data Constraint


10%的数据所有格子中权值均非负
另20%的数据n=2
另30%的数据k=0
100%的数据1≤n≤100,1≤m≤100,0≤k≤10 保证存在合法路径,数据有梯度,格子中每个元素的值绝对值不超过10000
 

Hint

除了第一行的第二个和第一行的第四个都要围起来才至少合法。

 

题解

  • 看完题目,然后随便画一画蚂蚁的行走路径可以发现,它的行走路径一定是
  • 类似于这种形状的,也就是一共有2*k+1个长方形组合形成的(k次分隔)
  • 那么答案就是要求2*k+1个矩阵内所有数之和最大值,考虑一下dp
  • 设f[i][j][k][h]为当前这个矩阵的右下角(i,j),是第k个矩阵,高度为h的最大值,g[i][j][k][h][0/1]为当前这个矩阵的右下角(i,j),是第k个矩阵,高度大于等于/小于h的最大值
  • 很容易就得出状态转移方程为f[i][j][k][h]=max(f[i][j-1][k][h],g[i][j-1][k-1][h][k%2])+sum[i][j]-sum[h-1][j](sum[i][j]表示第j列的前i行的和)
  • 什么意思呢?
  • ①f[i][j-1][k][h]也就是说矩阵还是原来那个,只是列多了一列
  • ②第二个就是从第j列开始新开一个新的矩阵,那么矩阵是一高一低分布的,这个矩阵是高是低取决于第k-1个是高是低
  • 按照定义的性质从高到低和从低到高分别扫一遍,转移为g[i][j][k][h][0]=max(g[i][j][k][h -1][0],f[i][j][k][h -1]),g[i][j][k][h][1]=max(g[i][j][k][h+1][1],f[i][j][k][h+1])

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 using namespace std;
 5 const int N=210,inf=1e9;
 6 int n,m,k,a[N][N],s[N][N],f[N][N][N],g[N][N][N][3],ans=-inf;
 7 int main()
 8 {
 9     scanf("%d%d%d",&n,&m,&k),k=k*2+1;
10     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];
11     for (int i=1;i<=k;i++) for (int j=1;j<=n;j++) f[0][i][j]=g[0][i][j][0]=g[0][i][j][1]=-inf;
12     for (int i=1;i<=n;i++)
13         for (int j=1;j<=m;j++)
14         {
15             for (int p=1;p<=k;p++)
16             {
17                 for (int q=i;q>=1;q--) f[j][p][q]=max(f[j-1][p][q],g[j-1][p-1][q][p%2])+s[i][j]-s[q-1][j];
18                 g[j][p][1][0]=-inf;
19                 for (int q=2;q<=i;q++) g[j][p][q][0]=max(g[j][p][q-1][0],f[j][p][q-1]);
20                 g[j][p][i][1]=-inf;
21                 for (int q=i-1;q>=1;q--) g[j][p][q][1]=max(g[j][p][q+1][1],f[j][p][q+1]);
22             }
23             ans=max(ans,max(f[j][k][i],g[j][k][i][0]));
24         }
25     printf("%d",ans);
26 }

 

posted @ 2019-01-29 21:26  BEYang_Z  阅读(277)  评论(0编辑  收藏  举报