"N <= 100;M <= 10"
这个形状基本就是状态压缩DP的标志(一个几百左右, 一个十几左右).
一层一层往下DP, 每层只受前两层影响, 经过计算, 每层最多有60种状态, 固复杂度为O(603*100).
详情见代码:
#include
<
iostream
>
using
namespace
std;
#define
max(a, b) ((a)>(b)?(a):(b))
int
n, m;
char
mat[
100
][
11
];
int
sta[
60
], sta_sum[
60
], sta_cnt;
//
二进制状态; 每个二进制状态中1的个数; 总状态数
int
pre[
60
][
60
], now[
60
][
60
];
int
get_1(
int
x)
//
统计二进制中1的个数
{
int
k;
for
(k
=
0
; x; k
++
) x
&=
(x
-
1
);
return
k;
}
void
get_sta(
int
space,
int
pre,
int
i)
//
计算单行所有可能的状态
{
if
(i
==
m)
{
sta[sta_cnt]
=
pre;
sta_sum[sta_cnt
++
]
=
get_1(pre);
return
;
}
get_sta(space
+
1
, pre, i
+
1
);
if
(space
>
1
)
get_sta(
0
, pre
|
1
<<
i, i
+
1
);
}
void
recur(
int
row)
{
int
hill
=
0
;
//
把单行的山转化成二进制
for
(
int
i
=
0
; i
<
m; i
++
)
if
(mat[row][i]
==
'
H
'
)
hill
+=
1
<<
i;
for
(
int
i
=
0
; i
<
sta_cnt; i
++
)
//
状态转移
{
if
(sta[i]
&
hill)
continue
;
for
(
int
j
=
0
; j
<
sta_cnt; j
++
)
{
for
(
int
k
=
0
; k
<
sta_cnt; k
++
)
{
if
(sta[i]
&
sta[j]
||
sta[j]
&
sta[k]
||
sta[i]
&
sta[k])
continue
;
now[i][j]
=
max(now[i][j], pre[j][k]);
}
now[i][j]
+=
sta_sum[i];
}
}
}
int
main()
{
scanf(
"
%d %d
"
,
&
n,
&
m);
for
(
int
i
=
0
; i
<
n; i
++
)
scanf(
"
%s
"
, mat[i]);
get_sta(
2
,
0
,
0
);
for
(
int
i
=
0
; i
<
n; i
++
)
{
recur(i);
memcpy(pre, now,
sizeof
(now));
memset(now,
0
,
sizeof
(now));
}
int
ans
=
0
;
for
(
int
i
=
0
; i
<
sta_cnt; i
++
)
for
(
int
j
=
0
; j
<
sta_cnt; j
++
)
ans
=
max(ans, pre[i][j]);
printf(
"
%d\n
"
, ans);
return
0
;
}