A. Tiling Dominoes |
Given a rectangular grid, with dimensions m x n, compute the number of ways of completely tiling it with dominoes. Note that if the rotation of one tiling matches another, they still count as different ones. A domino is a shape formed by the union of two unit squares meeting edge-to-edge. Equivalently, it is a matching in the grid graph formed by placing a vertex at the center of each square of the region and connecting two vertices when they correspond to adjacent squares. An example of a tiling is shown below.
The input will consist of a set of lines with m n, given the restriction n*m<101.
For each line of input, output the number of tilings in a separate line.
2 10 4 10 8 8
89 18061 12988816
N*M的棋盘用1*2的骨牌完全覆盖有多少种方法。
第一次做插头DP。插头DP适合在比较窄的棋盘上进行操作。假设行N比较大,列M比较小,这里用一个M位的状态表示当前状态,设第i行j列的格子编号是i*M+j,那么如果上一次的状态是s[i-M],s[i-M+1]...s[i-1],那么这次的状态就是s[i-M+1],s[i-M+2]...s[i],当前状态S的第j位就是s[i-j],s[i]为0代表编号为i的格子还没有被覆盖,1代表覆盖了。对于每个格子,可以横着放,竖着放,或者暂时不放。要注意判断一些不合法的情况的判断。因为每一步的状态只和上一步的状态有关,所以用滚动数组就行,最后答案是dp[cur][2^M-1]。复杂度O(2^M*N*M)。
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<vector> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; typedef long long LL; const int MAXN=11; const int MAXM=20010; int N,M,cur; LL dp[2][1<<MAXN]; //a是旧状态,b是新状态 void update(int a,int b){ if(b&(1<<M)) dp[cur][b^(1<<M)]+=dp[!cur][a]; } int main(){ freopen("in.txt","r",stdin); while(scanf("%d%d",&N,&M)!=EOF){ if(N<M) swap(N,M); cur=0; memset(dp,0,sizeof(dp)); dp[0][(1<<M)-1]=1; for(int i=0;i<N;i++) for(int j=0;j<M;j++){ cur=!cur; memset(dp[cur],0,sizeof(dp[cur])); for(int k=0;k<(1<<M);k++){ update(k,k<<1); //不放 if(i&&!(k&(1<<(M-1)))) update(k,(k<<1)^(1<<M)^1); //竖着放 if(j&&!(k&1)) update(k,(k<<1)^3); //横着放 } } printf("%lld\n",dp[cur][(1<<M)-1]); } return 0; }