在網上找了很多解題報告,看了很久才理解,不過理解之後代碼還是很好實現的><
還是對每個格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;}