bzoj3111 [Zjoi2013]蚂蚁寻路
zjoi2013的题终于做完了,拖了好久,觉得这份题质量挺高的,而且代码量都不是很大,zj的题还是比较注重思路的,而且都可以有不同的解法,甚至可以骗分= =。
这个题我一开始只能想出N^4的,后来参考某神的题解发现我多出来的那一维完全是没有用的......但是我还是想总结一下思路,毕竟这种2D的DP做的比较少,以免以后忘掉。
首先经过一些列的简化我们发现这个题实际就是求个凹凸不平的形状中的最大值,也就是一堆高度参差不齐的子矩形的和,这些子矩阵同底,高满足一高一低,一共要这样变2k次,也就是一共有2*k+1个矩形。
设f[i][j][k][h]表示以[i][j]为右下角的子矩阵,是当前的第k个子矩阵,最高点的坐标是h的最大和,然后mx[i][j][k][h][0/1]表示···最高点坐标不大于/不小于h的最大和。
于是有以下转移:
f[i][j][k][h]=max{ f[i][j-1][k][h] , mx[i][j-2][k-1][h][k%2] }+s[i][j]-s[h-1][j]
mx[i][j][k][h][0]=max{ mx[i][j][k][h-1][0] , f[i][j][k][h-1] }
mx[i][j][k][h][1]=max{ mx[i][j][k][h+1][1] , f[i][j][k][h+1] }
ans 用max{ f[j][p][i] , mx[j][p][i][0] }来更新
注意边界条件f[0][k][i]=mx[0][k][i][0]=mx[0][k][i][1]=-inf;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 120 7 #define inf 1000000000 8 using namespace std; 9 int f[maxn][24][maxn],a[maxn][maxn],s[maxn][maxn],mx[maxn][24][maxn][3]; 10 int n,m,p,ans; 11 12 int main() 13 { 14 scanf("%d%d%d",&n,&m,&p); 15 p=p*2+1; 16 for (int i=1;i<=n;i++) 17 for (int j=1;j<=m;j++) 18 scanf("%d",&a[i][j]),s[i][j]=s[i-1][j]+a[i][j]; 19 for (int i=1;i<=n;i++) 20 for (int k=1;k<=p;k++) 21 f[0][k][i]=mx[0][k][i][0]=mx[0][k][i][1]=-inf; 22 ans=-inf; 23 for (int i=1;i<=n;i++) 24 for (int j=1;j<=m;j++) 25 { 26 for (int k=1;k<=p;k++) 27 { 28 for (int h=i;h;h--) 29 f[j][k][h]=max(f[j-1][k][h],mx[j-1][k-1][h][k%2])+s[i][j]-s[h-1][j]; 30 mx[j][k][1][0]=-inf; 31 for (int h=2;h<=i;h++) 32 mx[j][k][h][0]=max(mx[j][k][h-1][0],f[j][k][h-1]); 33 mx[j][k][i][1]=-inf; 34 for (int h=i-1;h;h--) 35 mx[j][k][h][1]=max(mx[j][k][h+1][1],f[j][k][h+1]); 36 } 37 ans=max(ans,max(f[j][p][i],mx[j][p][i][0])); 38 } 39 printf("%d\n",ans); 40 return 0; 41 }
不行,这种2D的dp我做得实在是太少了...
AC without art, no better than WA !