二维动态规划,设
d
p
(
i
,
j
)
\ dp\left(i,j\right)
dp(i,j)为以
(
i
,
j
)
\ \left(i,j\right)
(i,j)为右下顶点的正方形的最大边长。则容易想到
d
p
(
i
,
j
)
\ dp\left(i,j\right)
dp(i,j)仅与
d
p
(
i
−
1
,
j
)
\ dp\left(i-1,j\right)
dp(i−1,j)、
d
p
(
i
,
j
−
1
)
\ dp\left(i,j-1\right)
dp(i,j−1)和
d
p
(
i
−
1
,
j
−
1
)
\ dp\left(i-1,j-1\right)
dp(i−1,j−1)有关。
而我们知道,倘若存在以
(
i
,
j
)
\ \left(i,j\right)
(i,j)为右下顶点的正方形,则其边长必在
[
1
,
m
i
n
(
d
p
(
i
−
1
,
j
)
,
d
p
(
i
,
j
−
1
)
)
]
\ \left[1,min\left(dp\left(i-1,j\right),dp\left(i,j-1\right)\right)\right]
[1,min(dp(i−1,j),dp(i,j−1))]。确定了边长范围以后,自然可以就通过遍历
d
p
(
i
−
m
,
j
−
m
)
\ dp\left(i-m,j-m\right)
dp(i−m,j−m)得到最优解了。
状态转移方程如下:
d
p
(
i
,
j
)
=
{
0
if
p
[
i
]
[
j
]
=
=
0
1
if
i
=
=
0
o
r
j
=
=
0
a
n
d
p
[
i
]
[
j
]
=
=
1
m
a
x
(
m
)
else
f
o
r
m
i
n
[
1
,
m
i
n
(
d
p
(
i
−
1
,
j
)
,
d
p
(
i
,
j
−
1
)
)
]
a
n
d
p
(
i
−
m
,
j
−
m
)
=
=
1
dp(i,j)=\begin{cases}0 &\text{if } p[i][j]==0\\1 &\text{if } i==0 \ or\ j==0\ and\ p[i][j]==1 \\ max(m) &\text{else}\ for\ m \ in \left[1,min\left(dp\left(i-1,j\right),dp\left(i,j-1\right)\right)\right] and\ p\left(i-m,j-m\right)==1\end{cases}
dp(i,j)=⎩⎪⎨⎪⎧01max(m)if p[i][j]==0if i==0 or j==0 and p[i][j]==1else for m in[1,min(dp(i−1,j),dp(i,j−1))]and p(i−m,j−m)==1
潜在优化:
- 占个坑先。。。
代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
int r, c;
int p[100][100] = { 0 };
int dp[100][100] = { 0 };
int findans() {
int result = 0;
for (int i = 1; i < r; ++i) {
for (int j = 1; j < c; ++j) {
if (p[i][j]) {
int subl = min(dp[i - 1][j], dp[i][j - 1]);
for (int m = 1; m <= subl; ++m) {
if (!dp[i - m][j - m]) {
subl = m - 1;
break;
}
}
dp[i][j] = subl + 1;
result = max(result, dp[i][j]);
}
}
}
//return (result - 1) * 4; //求周长
return result; //求边长
}
int main(){
cin >> r >> c;
for (int i = 0; i < r; ++i) {
for (int j = 0; j < c; ++j) {
cin >> p[i][j];
if ((i == 0 || j == 0) && p[i][j]) dp[i][j] = 1;
}
}
cout << findans() << endl;
return 0;
}