标签:
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 12854 | Accepted: 7486 |
Description
Input
Output
Sample Input
1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0
Sample Output
1 0 1 2 3 5 144 51205
题目描述:
之前做过用1*2的骨牌覆盖2*n的棋盘,考虑第一个骨牌的方法,要么两个横着放,要么一个竖着放,
如果是n*m的棋盘,那么它还是可以用2*n的棋盘(每两行)递推过去的,每行(包括第一行)有三种选择,横着放,竖着放,
不放,如果用1表示横着放和竖着放的第二个,0表示竖着放的第一个和不放,每次都是两行之间的转换,
找出可以互相转换的状态就可以,采用深搜,
设pre和now,
如果当前位置横着放,状态为11,那么上一行也必须是11
如果当前位置竖着放,状态为1,上一行为0
如果当前位置不放,那么上一行此位置为1,当前位置为0
,然后从第0行全为1开始,因为这样转换之后的状态才能构成一个完整的棋盘。
#include <iostream> #include <cstdio> #include <cstring> #define maxn 12 #define LL long long using namespace std; int h,w; LL d[maxn][1<<maxn]; LL cnt; LL EX[100000000][2]; void dfs(int l,int now,int pre) { if(l>w) return ; if(l==w) { EX[cnt][0]=pre; EX[cnt++][1]=now; //cout<<pre<<" "<<now<<endl; return ; } dfs(l+2,((now<<2 )|3),((pre<<2) | 3)) ; //横放 dfs(l+1,((now<<1) |1),(pre<<1) ) ; //竖放 dfs(l+1, (now<<1) , ((pre<<1)| 1)) ; //不放 } void solve() { int s=(1<<w)-1; d[0][s]=1; for(int i=0;i<h;i++) for(int j=0;j<cnt;j++) { d[i+1][EX[j][1]]+=d[i][EX[j][0]]; } // for(int j=0;j<cnt;j++) // printf("%d %d\n",EX[j][1],EX[j][0]); printf("%lld\n",d[h][s]); } int main() { while(~scanf("%d%d",&h,&w) && (h!=0 && w!=0)) { memset(d,0,sizeof(d)); // if(h>w) // swap(h,w); cnt=0; dfs(0,0,0); solve(); } return 0; }
标签:
原文地址:http://www.cnblogs.com/xianbin7/p/4546305.html