http://poj.org/problem?id=1185
状态:
dp[i][j][k]表示第i行的状态为是s[j] 第i-1的状态为s[k];
状态压缩:
把每行的状态状态缩成一个2进制 逐行DP
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 105;
int n,m;
int dp[maxn][65][65]; //dp[i][j][k]表示第i行的状态为是s[j] 第i-1的状态为s[k];
int map[maxn],sum[65],s[65]; //s存状态 最多60种
int tot;
int Max( int a,int b )
{
return a>=b?a:b;
}
//状态s[x]是否造成行冲突
bool ok(int x)
{
if( x& (x<<1) ) return false;
if( x& (x<<2) ) return false;
return true;
}
//状态s[x]下有多少个1
int getsum(int x)
{
int sum = 0;
while( x > 0 )
{
if( x&1 ) sum ++;
x >>= 1;
}
return sum;
}
void find()
{
memset( s,0,sizeof(s) );
for( int i=0; i<(1<<m); i++ ) //i枚举所有m位的二进制数
{
if( ok(i) )
{
s[tot] = i;
sum[tot++] = getsum(i);
}
}
}
int main()
{
//freopen("data.in","r",stdin);
char temp;
while( scanf("%d%d",&n,&m) != EOF )
{
memset( dp,-1,sizeof(dp) );
for( int i = 0; i < n; i ++ )
{
getchar();
for( int j = 0; j < m; j ++ )
{
scanf("%c",&temp);
if( temp == 'H' )
map[i] = map[i]|(1<<j);
}
}
tot = 0;
find();
//1. 初始化第0行状态(只考虑有效状态,无效状态为-1)
for( int i = 0; i < tot; i ++ )
{
if( !( s[i] & map[0] ) )
dp[0][i][0] = sum[i];
}
//2. 计算第1~n-1行状态(碰到无效状态,continue)
for( int i = 1; i < n; i ++ )
{
for( int j = 0; j < tot; j ++ )//枚举第i行的状态 s[j]
{
if( map[i] & s[j] ) //通过地形排除部分第i行的状态
continue;
for(int p = 0; p < tot; p ++) //枚举第i-1行状态 s[p]
{
if( s[j] & s[p] ) continue; //r与i-1没有想接触的
for( int q=0; q < tot; q ++) //枚举第i-2行状态s[q]
{
if( (s[p] & s[q]) || (s[j] & s[q]) ) //排除i-1行与i-1行跟i行冲突
continue;
if( dp[i-1][p][q] == -1 ) //所有不可能的情形dp[i][j][k]都为-1(初始化的值)
continue;
dp[i][j][p] = Max( dp[i][j][p], dp[i-1][p][q] + sum[j]);
}
}
}
}
int ans = 0;
for( int i = 0; i < tot; i ++ )
{
for( int j = 0; j < tot; j ++ )
{
ans = Max( ans,dp[n-1][i][j] );
}
}
printf("%d\n",ans);
}
return 0;
}