The input contains several test cases. Each test case is made up of two integer numbers: the height h and the width w of the large rectangle. Input is terminated by h=w=0. Otherwise, 1≤h,w≤111\leq h,w\leq 111≤h,w≤11.
For each test case, output the number of different ways the given rectangle can be filled with small rectangles of size 2 times 1. Assume the given large rectangle is oriented, i.e. count symmetrical tilings multiple times.示例1
1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0
1 0 1 2 3 5 144 51205
地图形的状压DP,就得设计01有时候比较简单,但这题就比较复杂
如下表示1*2立柱
0 1
如下表示2*1横杆
11
可以想到,这样表示 第一行的状态 i 和第二行的状态 j 相或 i | j 一定是 (1 <<m) - 1,也就是全都是1
i & j 会消除所有的立柱,怎么让剩下的 1 满足都是横杆的合法情况?
只剩下横杆,但是要考虑到,如果是上上一行的立柱到了上一行,导致上一行某个位置是1,当前这一行这个位置 却是1,而旁边也有两个1,就会有连续三个1 。这种情况就是非法的,
所以要写个函数,看看当前状态是不是都是连续偶数个1 就可以了。
同理初始状态也要把这个考虑进去。第一行的所有满足连续偶数个1的都是合法状态。
设dp[i][j] 表示 i 行 状态 j 的合法方案数 初始状态:if(check(i ) ) dp[1][i] = 1; 状态转移:if(check(j&k) dp[i][j] = dp[i-1][k]
//-------------------------代码---------------------------- //#define int ll const int N = 2e6+10; ll n,m,dp[14][(1<<11) + 10]; bool check(int x) { while(x) { int temp = 0; while(x & 1) { x >>= 1; temp ++ ; } if(temp % 2) return 0; x >>= 1; } return 1; } void solve() { ms(dp,0); if(n == 1) { if( m % 2 ) { cout<<0<<endl; } else { cout<<1<<endl; }rt } fo(i,0,(1<<m)-1) { if(check(i))dp[1][i] = 1; } fo(i,2,n+1) { fo(j,0,(1<<m) - 1) { fo(k,0,(1<<m) - 1) { if((j | k) != (1 <<m) - 1) continue; if(check(j & k)) dp[i][j] += dp[i-1][k]; } } } cout<<dp[n][(1<<m) - 1]<<endl; } signed main(){ AC(); clapping();TLE; // int t;cin>>t;while(t -- ) while(cin>>n>>m,n,m) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------