"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;
}
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;
}