[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 }

 


注意!

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



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