"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(
200);
    
    
for (int i = 0; i < n; i++)
    {
        recur(i);
        memcpy(pre, now, 
sizeof(now));
        memset(now, 
0sizeof(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;
}