题目描述
回到家中的猫猫把三桶鱼全部转移到了她那长方形大池子中,然后开始思考:到底要以何种方法吃鱼呢(猫猫就是这么可爱,吃鱼也要想好吃法 ^_*)。她发现,把大池子视为01矩阵(0表示对应位置无鱼,1表示对应位置有鱼)有助于决定吃鱼策略。
在代表池子的01矩阵中,有很多的正方形子矩阵,如果某个正方形子矩阵的某条对角线上都有鱼,且此正方形子矩阵的其他地方无鱼,猫猫就可以从这个正方形子矩阵“对角线的一端”下口,只一吸,就能把对角线上的那一队鲜鱼吸入口中。
猫猫是个贪婪的家伙,所以她想一口吃掉尽量多的鱼。请你帮猫猫计算一下,她一口下去,最多可以吃掉多少条鱼?
输入格式
有多组输入数据,每组数据:
第一行有两个整数n和m(n,m≥1),描述池塘规模。接下来的n行,每行有m个数字(非“0”即“1”)。每两个数字之间用空格隔开。
对于30%的数据,有n,m≤100
对于60%的数据,有n,m≤1000
对于100%的数据,有n,m≤2500
输出格式
只有一个整数——猫猫一口下去可以吃掉的鱼的数量,占一行,行末有回车。
输入输出样例
输入 #1
4 6 0 1 0 1 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 1 1 0 1 0
输出 #1
3
说明/提示
右上角的
1 0 0 0 1 0 0 0 1
思路
考虑这样一个问题:如果以 f[i][j][1|0] 来表示取到第 (i, j) 个位置时所能取到的最长的对角线长度,0表示左上到右下,1表示右上到左下方向,什么时候\怎样来更新 f 的值。
首先如果以 之前那道最大正方形的方法来做,只能过第一个点 1 1 0 这个数据。因为会发现这道题比最大正方形多了一个限制条件,就是在这个对角线确定的大矩形中,除了这条对角线之外不能有多余的1.
所以在从右上或左上转移时,要多加一个这个条件对状态的影响。
这个条件有什么影响?
注意到因为动态规划是由 1 ~ n 这样来推理,所以可以分析在边界 1 时的影响即可。
对于以下样例分析
1 0 0
0 1 0
0 0 1
当 i = 1, j = 1 时,显然 f = 1
当 i = 2, j = 2 时,如果 a[2][2] 的上方和右方都没有 1 ,则 f[i][j] = f[i-1][j-1] + 1 ;
如果 a[2][2] 的右方和上方有 1 ,显然 f[i][j] = 1 且应该作为一段新的开始。
由是可以推到 n 。
CODE
#include
<
bits/stdc++.h
>
#define
dbg(
x
) cout
<<
#x
<<
"
=
"
<< x
<< endl
#define
eps
1
e
-
8
#define
pi
acos(
-
1.0
)
using
namespace std
;
typedef
long
long LL
;
const
int inf
=
0x
3f3f3f3f
;
template
<
class T
>
inline
void
read(T
&
res
)
{
char c
;T flag
=
1
;
while((c
=
getchar())
<
'
0
'
||c
>
'
9
'
)if(c
==
'
-
'
)flag
=-
1
;res
=c
-
'
0
'
;
while((c
=
getchar())
>=
'
0
'
&&c
<=
'
9
'
)res
=res
*
10
+c
-
'
0
'
;res
*=flag
;
}
namespace _buff
{
const
size_t BUFF
=
1
<<
19
;
char
ibuf
[BUFF
],
*ib
= ibuf
,
*ie
= ibuf
;
char
getc()
{
if
(ib
== ie
)
{
ib
= ibuf
;
ie
= ibuf
+
fread(ibuf
,
1
, BUFF
, stdin
);
}
return ib
== ie
?
-
1
:
*ib
++
;
}
}
int
qread()
{
using
namespace _buff
;
int ret
=
0
;
bool pos
=
true
;
char c
=
getc();
for
(;
(c
<
'
0
'
|| c
>
'
9
'
)
&& c
!=
'
-
'
; c
=
getc())
{
assert(
~c
);
}
if
(c
==
'
-
'
)
{
pos
=
false
;
c
=
getc();
}
for
(; c
>=
'
0
'
&& c
<=
'
9
'
; c
=
getc())
{
ret
=
(ret
<<
3
)
+
(ret
<<
1
)
+
(c
^
48
);
}
return pos
? ret
:
-ret
;
}
const
int maxn
=
2577
;
int n
,m
;
int
a
[maxn
][maxn
];
int
f
[maxn
][maxn
][
2
];
int
main()
{
//freopen("data.txt", "r", stdin);
read(n
);
read(m
);
for
(
int i
=
1
; i
<= n
;
++i
)
{
for
(
int j
=
1
; j
<= m
;
++j
)
{
read(
a
[i
][j
]);
}
}
int ans
=
0
;
for
(
int i
=
1
; i
<= n
;
++i
)
{
for
(
int j
=
1
; j
<= m
;
++j
)
{
if(
a
[i
][j
])
{
int up
=
0
, rig
=
0
;
for
(
int k
= i
-
1
; k
>=
1
;
--k
)
{
if(
a
[k
][j
])
{
break;
}
++up
;
}
for
(
int k
= j
+
1
; k
<= m
;
++k
)
{
if(
a
[i
][k
])
{
break;
}
++rig
;
}
f
[i
][j
][
1
]
=
min(
f
[i
-
1
][j
+
1
][
1
],
min(up
, rig
))
+
1
;
//f[i][j][1] = min(f[i - 1][j + 1][1], min(up, rig)) + 1;
}
//printf("f[%d][%d]:%d\n",i, j, f[i][j][0]);
ans
=
max(ans
,
max(
f
[i
][j
][
0
],
f
[i
][j
][
1
]));
}
for
(
int j
= m
; j
>=
1
;
--j
)
{
int up
=
0
, lef
=
0
;
if(
a
[i
][j
])
{
for
(
int k
= i
-
1
; k
>=
1
;
--k
)
{
if(
a
[k
][j
])
{
break;
}
++up
;
}
for
(
int k
= j
-
1
; k
>=
1
;
--k
)
{
if(
a
[i
][k
])
{
break;
}
++lef
;
}
f
[i
][j
][
0
]
=
min(
f
[i
-
1
][j
-
1
][
0
],
min(up
, lef
))
+
1
;
// if(i == 3 && j == 6) {
// printf("up:%d lef:%d f[3][6][0]:%d\n",up, lef, f[3][6][0]);
// }
// if(i == 2 && j == 5) {
// printf("up:%d lef:%d f[2][5][0]:%d\n",up, lef, f[2][5][0]);
// }
// if(i == 1 && j == 4) {
// printf("up:%d lef:%d f[1][4][0]:%d\n",up, lef, f[1][4][0]);
// }
}
ans
=
max(ans
,
max(
f
[i
][j
][
0
],
f
[i
][j
][
1
]));
}
}
cout
<< ans
<< endl
;
return
0
;
}