【BZOJ3111】[ZJOI2013] 蚂蚁寻路(DP水题)

点此看题面(然而并没有题面

大致题意: 有一张棋盘,每个格子有一个权值(可能为负)。一只蚂蚁从任意一个格点出发向上走,按两次右转、两次左转的顺序转弯(每次转弯前可以走任意长度),并在最后一次转弯(一定是右转)时右转三次。已知:蚂蚁不会在一个位置转多次;除起点外蚂蚁不会重复经过任一格点,且蚂蚁最终会回到起点。给出蚂蚁左转的次数/2的值,求蚂蚁所经过路线围成封闭图形的最大值。

前言

这是少数我能自己做出来的(DP)题。。。

我能做出来的(DP)题=(DP)水题。

大致思路

题面很复杂,但稍微画画图分析一下,就会发现蚂蚁围成的图形必然是一条水平线之上高-低-高-低-...-高的一个图形。说起来有点抽象,但实际上就是长这个样子:(好像画得也挺抽象。。。

因此,我们可以枚举行数(i),然后设(f_{j,p,x})表示(DP)到第(j)列,顶端在第(p)行,转弯状态为(x)时的方案数((x=0,2,...,2k)表示右转,(1,3,...,2k-1)表示左转)。

(f_{j,p,x})表示(DP)到第(j)列,顶端在第(p)行,转弯状态为(x)时的方案数((x=0,2,...,2k)表示右转,(1,3,...,2k-1)表示左转)。

(t=sum_{w=p}^ia_{w,j})(可以在(DP)同时维护),则有两种方式转移:

  • 从前一列到这一列没有转弯,则(f_{j,p,x}=f_{j-1,p,x}+t)
  • 前一个是没转弯,这一个当然是转弯了啊。。。但转弯又分两种:
    1. 高度增加((x)为偶数):(f_{j,p,x}=max_{w=p+1}^if_{j-1,w,x-1}+t)
    2. 高度降低((x)为奇数):(f_{j,p,x}=max_{w=1}^{p-1}f_{j-1,w,x-1}+t)

其中(max)的值我们可以事先预处理前缀(max)和后缀(max)

注意一些细节,例如第一列无法从前一列转移,可以单独处理。

然后,对于每一列都要考虑(x=0)的特殊情况,因为此时我们可以以该列作为起始列,即初始化(f_{j,p,0}=t)

具体实现详见代码。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100
#define K 10
#define Gmax(x,y) (x<(y)&&(x=(y)))
using namespace std;
int n,m,k,a[N+5][N+5],f[N+5][N+5][2*K+5],g[N+5][N+5][2*K+5],h[N+5][N+5][2*N+5];
int main()
{
	RI i,j,p,x,t;scanf("%d%d%d",&n,&m,&k);
	for(i=1;i<=n;++i) for(j=1;j<=m;++j) scanf("%d",&a[i][j]);
	RI ans=-1e9;for(i=1;i<=n;++i)
	{
		for(t=0,p=i;p;--p) for(f[1][p][0]=(t+=a[p][1]),//初始化第一列
			x=1;x<=2*k;++x) f[1][p][x]=g[1][p][x]=h[1][p][x]=-1e9;
		for(g[1][i][0]=f[1][i][0],p=i-1;p;--p) g[1][p][0]=max(g[1][p+1][0],f[1][p][0]);
		for(h[1][1][0]=f[1][1][0],p=2;p<=i;++p) h[1][p][0]=max(h[1][p-1][0],f[1][p][0]);
		for(j=2;j<=m;++j)//处理之后的每一列
		{
			for(t=0,p=i;p;--p)//枚举顶端所在行
			{
				for(x=0;x<=2*k;++x) f[j][p][x]=g[j][p][x]=h[j][p][x]=-1e9;//清空
				for(f[j][p][0]=(t+=a[p][j]),x=0;x<=2*k;++x)//维护t,注意特殊处理x=0
					Gmax(f[j][p][x],f[j-1][p][x]+t),//直接转移
					x&&!(x&1)&&p^i&&Gmax(f[j][p][x],g[j-1][p+1][x-1]+t),//高度增加
					x&1&&p^1&&Gmax(f[j][p][x],h[j-1][p-1][x-1]+t);//高度降低
			}
			for(x=0;x<=2*k;++x) for(g[j][i][x]=f[j][i][x],
				p=i-1;p;--p) g[j][p][x]=max(g[j][p+1][x],f[j][p][x]);
			for(x=0;x<=2*k;++x) for(h[j][1][x]=f[j][1][x],
				p=2;p<=i;++p) h[j][p][x]=max(h[j][p-1][x],f[j][p][x]);
		}
		for(j=1;j<=m;++j) for(p=i;p;--p) Gmax(ans,f[j][p][2*k]);//统计答案
	}return printf("%d",ans),0;
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3111.html