您的位置:首页 > 其它

POJ 2411 Mondriaan's Dream 状态压缩(DP)

2011-09-22 18:57 369 查看
题意:给出一个h*w的矩阵,用长为1宽为2,或者长为2,宽为1的骨牌来填满,求方案数。

题解:放骨牌的时候要么横着放,要么竖着放。现在来规定放置方式,对于矩阵上任意一个点[i,j],在上面放置一块骨牌,如果横着放,那么占据[i,j], [i,j+1];如果竖着放则占据[i,j] ,[i-1,j],并且当第 i 行放置完成后第 i-1之前的所有位置行必须是被骨牌填满的。



#include <algorithm>
#include <iostream>
using namespace std;

#define bit(x) (1<<x)
#define lint __int64

int state, h, w;
lint dp[12][1<<12];

bool check ( int st ) /* 检验第一行的放置方案 */
{
for ( int i = 0; i < w; i++ )
{
if ( 0 == (st & bit(i)) ) /* 第i点为0,那么留给它的下一行来覆盖,因为竖着放是覆盖点[i,j],[i-1,j],可行 */
continue;
if ( i == w - 1 ) /* 为1且已经是最右边的点,不可能再横着放下一块骨牌了,不可行 */
return false;
if ( ! (st & bit(1+i)) ) /* 本身为1且下一个点为0,不满足横着放的条件,因为横着放覆盖点[i,j],[i,j+1],不可行*/
return false;
i++; /* 到这一步说明是点i横着放下一块骨牌,那么点i,和点i+1都是1,直接跳到i+2(两次i++) */

}
return true;
}

bool isLeagal ( int st1, int st2 ) /* 检验状态转移是否合法 */
{
for ( int i = 0; i < w; i++ )
{
if ( (st1 & bit(i)) != 0 )
{
if ( (st2 & bit(i)) != 0 )
{
if ( i == w - 1 )
return false;
if ( 0 == (st2 & bit(i+1)) || 0 == (st1 & bit(i+1)) )
return false;
i++;
}
}
else
{
if ( (st2 & bit(i)) == 0 )
return false;
}
}
return true;
}

int main()
{
while ( scanf("%d %d", &h, &w) && (h+w) )
{
if ( (h * w) % 2 )
{
printf("0\n");
continue;
}
if ( w > h ) swap(w,h);

int i, j, k;
state = (1 << w) - 1;
memset(dp,0,sizeof(dp));

for( i = 0; i <= state; i++ )
if ( check(i) ) dp[h][i] = 1;

for ( i = h-1; i >= 1; i-- )
{
for ( j = 0; j <= state; j++ )
{
for ( k = 0; k <= state; k++ )
if ( isLeagal ( k, j ) )
dp[i][j] += dp[i+1][k];
}
}
printf("%I64d\n",dp[1][state]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: