简单的状态压缩dp
题意: 给出一个n*m的矩形,(n和m都不大于11),现在想往这个举行里边放1*2的小矩形,问有多少中方法。
思路: 由于n的m都不大,因此我们可以想到用压缩dp的方法解决, 一行一行的处理, 每一行有很多状态,这一行的状态用上一行的状态转化过来。 dp[i][j]表示在第i行,状态时j时的情况数,这里的状态就是如果当前行这个位置放了东西那么这个位置就用1来表示,否则就用0来表示。 上一层的0,必须要用2*1的方法来填补,这样才不会重复计数, 也不会少计数,因为如果用1*2的矩形,可以看成是另外一个状态。
如果上一层的j能够转化成这一层的k ,那么dp[i][k] += dp[i-1][j];
AC 代码:
View Code
#include <iostream> #include <cstdio> #include <string> #include <cstring> using namespace std; typedef long long LL; const int N = 12; LL dp[N][1<<N]; int n, m; void solve() { if(n*m % 2) { printf("0\n"); return; } int s, y = (1<<m)-1; memset(dp,0,sizeof(dp)); dp[0][y] = 1; bool flag; for(int i=1; i<=n; i++) { for(int j=0; j<=y; j++) { for(int k=0; k<=y; k++) { if((j|k) == y) { flag = 1; s = k; for(int w=0; w<m;w++) { if(!((1<<w)&j) ) s ^= (1<<w); } for(int w=0; w<m; w++) { if(s&(1<<w)) { if(s&(1<<(w+1)) ) { w++; } else flag=0; } } if(flag) { dp[i][k] += dp[i-1][j]; } } } } } printf("%I64d\n",dp[n][y]); } int main() { while(scanf("%d%d", &n, &m) != EOF) { if(n == 0 && m == 0) break; solve(); } return 0; }


浙公网安备 33010602011771号