在网上找了很多解题报告,看了很久才理解,不过理解之后代码还是很好实现的><
还是对每个格2种状态 ,1表示被占 , 0表示不被占 ,
对每一行可以做横放 , 竖放 , 不放, 3种操作, 没种操作都要求出对应上一行的状态, 比如若竖放 , 上一行的状态就必须是0 , 既没被占用,横放和不放对应的上一行必须是1,这样才能将所有的格子都填满,其次对第一行只有横放和不放2种操作, 对状态的转换自己YY下就可以出来,对于状态的转换,是树状的, 所以用DFS更好理解
#include <cstdio> #include <cstring> typedef long long ll; const int maxn=1<<12; ll dp[13][maxn]; int n,m; void dfs(int c , int opt)//only horizontal lie and not lie in first row; { if(c>=m) { if(c==m)dp[0][opt]++; return; } dfs(c+1 , opt<<1); dfs(c+2 , opt<<2|3); } void DFS(int r , int c , int pre , int opt) //这里的pre并非要对上一行处理,而是根据本行的状态求出上一行对应状态,以便更新DP[][] { if(c>=m) { if(c==m)dp[r][opt]+=dp[r-1][pre]; return ; } DFS(r , c+1 , pre<<1 , opt<<1|1);//vetical DFS(r , c+2 , pre<<2|3 , opt<<2|3);//horizoncal DFS(r , c+1 , pre<<1|1 , opt<<1);// } void debug () { for (int i=0 ; i<n ; ++i) { for (int j=0 ; j<(1<<m) ; ++j) { printf("j=%o %d ",j,dp[i][j]); } puts(""); } } int main () { int cas; scanf("%d",&cas); while (cas--) { scanf("%d%d",&n,&m); memset (dp , 0 , sizeof(dp)); if((n&1) && (m&1)){printf("0\n"); continue ;} if(m>n)n^=m^=n^=m;//行是指数级 , 列式线性的 dfs(0,0); for (int i=1 ; i<n ; ++i) DFS(i , 0 , 0 , 0); ll ans=0; /*for (int i=0 ; i<(1<<m) ; ++i) { ans+=dp[n-1][i]; }*/ //debug (); //printf("%lld\n",ans); //本来以为sigma(dp[n-1][i])是答案,debug的时候发现最后一行全部放满的dp[n-1][(1<<m)-1]才是答案 printf("%lld\n",dp[n-1][(1<<m)-1]); } return 0; }