POJ_2411 MondriaansDream ( 状压dp )

文章目录

vj or poj

题意

给定 n * m 的方格棋盘, 用 1*2 的矩形不重叠地覆盖这个棋盘, 求覆盖满的方案数

题解

位运算结合状态压缩, 比较复杂

引用

   二进制数(####)代表填完一行后这一行的状态,填满的地方为1,未填的地方为0。

   显然在填第i行时,能改变的仅为第i-1行和第i行,因此要满足在填第i行时,第1~i-2行已经全部填满。

   DFS一行的状态,要是填完第i行时,第i-1行被填满。

   因此两行的状态(p1,p2)满足,~p1 = p2;

  

   DFS出所有满足条件的状态对(P1,P2)

   ①第i行第k位为1,第i-1行第k位为0。(一块骨牌竖直放置)

             dfs(k+1,last<<1,now<<1 | 1)

   ②第i行第k位为0,第i-1行第k位为1。 (第i行空出第k位)

             dfs(k+1,last<<1 | 1,now<<1)

   ③骨牌横向放置。

            bfs (k + 2, last << 2 | 3, now << 2 | 3)

   

   转移方程:F[i][sp1]=∑f[i-1][sp2]

代码

// #include <bits/stdc++.h> 
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; 
#define rg register 
#define sc scanf 
#define pf printf 
typedef long long ll; 

int n, m, 
    pos;
ll f[12][1 << 12];

void dfs ( int k, int last, int now ) {
	if ( k == m )     f[pos][now] += f[pos - 1][last];
	if ( k > m ) return;
	dfs ( k + 1, last << 1    , now << 1 | 1 );
	dfs ( k + 1, last << 1 | 1, now << 1     );
	dfs ( k + 2, last << 2 | 3, now << 2 | 3 );
}

int main ( ) {  // freopen( "F:\\in\\.txt" , "r" , stdin ); 

	while ( ~sc ( "%d %d", &n, &m ) ) {
		if ( n == 0 ) break;

		if ( n > m )  swap ( n, m );
		memset ( f, 0, sizeof f );

		f[0][(1 << m) - 1] = 1;
		for ( pos = 1; pos <= n; pos++ )
			dfs ( 0, 0, 0 );
            
		pf ( "%lld\n", f[n][(1 << m) - 1] );
	}


    return 0 ; 
} 
发布了160 篇原创文章 · 获赞 146 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44510468/article/details/103498326