一道不太明顯的dp,dp[i][j]的含義是,以i,j爲右下角的福字的大小。
首先進行預處理,兩個二維數組。shang[i][j]表示從座標ij的元素開始向上尋找,能找到多少個元素使他們都滿足map[i-1][j] + 1 == map[i][j],比如這個
1 2 3
2 3 4
3 5 5
他的shang數組就是
1 1 1
2 2 2
3 3 3
同理,再構建一個左數組。
然後我們就可以找到這樣的轉移方程
if(map[i][j] == map[i-1][j-1] + 2){
dp[i][j] = min(dp[i-1][j-1]+1,min(shang[i][j],zuo[i][j]));
}
ac代碼
#include <iostream>
#include <math.h>
#include <iomanip>
#include <string>
#include <cstdio>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#define INF 0x3f3f3f3f
#define N 2010
#define M 998244353
#define ll long long
using namespace std;
int n;
int map[N][N];
int shang[N][N],zuo[N][N];
int dp[N][N];
int main() {
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
scanf("%d",&map[i][j]);
}
}
int tmp = 1;
for(i=1;i<=n;i++){
tmp = 1;
zuo[i][1] = tmp;
for(j=2;j<=n;j++){
if(map[i][j] == map[i][j-1] + 1){
tmp++;
zuo[i][j] = tmp;
}else{
tmp = 1;
zuo[i][j] = tmp;
}
}
}
for(j=1;j<=n;j++){
tmp = 1;
shang[1][j] = tmp;
for(i=2;i<=n;i++){
if(map[i][j] == map[i-1][j] + 1){
tmp++;
shang[i][j] = tmp;
}else{
tmp = 1;
shang[i][j] = tmp;
}
}
}
for(i=1;i<=n;i++){
dp[i][1] = dp[1][i] = 1;
}
int ans = 0;
for(i=2;i<=n;i++){
for(j=2;j<=n;j++){
if(map[i][j] == map[i-1][j-1] + 2){
dp[i][j] = min(dp[i-1][j-1]+1,min(shang[i][j],zuo[i][j]));
ans = max(ans,dp[i][j]);
}else
{
dp[i][j] = 1;
ans = max(ans,dp[i][j]);
}
}
}
printf("%d\n",ans);
return 0;
}
一開始想的是按照dp[i-1][j]或者dp[i][j-1]構造轉移方程,後來發現很麻煩而且沒有必要。
這道題的數據比較松,有些錯誤的轉移方程也可以跑過。