[BZOJ 3111] ZJOI 2013 螞蟻尋路 · 動態規划


BZOJ上沒有題目,也是有點小坑……

那么自己在草稿紙上畫畫寫寫就很容易發現,這題其實是要你在一個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 <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
#define inf 1000000000

const int maxn=120;
int n,m,k,ans,a[maxn][maxn],f[maxn][25][maxn],g[maxn][25][maxn][2],s[maxn][maxn];

int main(){
scanf("%d%d%d",&n,&m,&k);
k=k*2+1;
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];
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;
ans=-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;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;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;
}


 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com