关于“我读过很多书,到后来大部分都被我忘记了,那阅读的意义是什么?”的疑问,我看过最巧妙的一个回答:当我还是个孩子的时候,我吃过很多的食物,大部分已经一去不复返而且被我忘记了,但可以肯定的是,它们中的一部分已经成长为我的骨头和肉。阅读对你的思想的改变也是如此。
填充的方法:
每個點三種情況,
1)是一個豎著的1*2的長方形的上半部分,對下一行限制是必須補全該長方形,用二進制1來表示
2)是一個豎著的1*2的長方形的下半部分,對下一行無限制,用0表示
3)是一個橫著的1*2的長方形的一部分,對下一行沒有限制,用0表示
按行號dp,f [ i ] [ j ]表示第 i 行狀態為 j 的方案數,
第 i-1 行的狀態 k 能轉移到第 i 行狀態為 j 當且僅當:
1.j 和 k 執行按位与結果為0(保證每個數字1的下方必須是0)
2.j 和 k 執行按位或結果每一段連續的0都必須有偶數個(若干橫著的1*2長方形)
(按位或后就去掉了和上面一起成為一個長方形的情況)
#include<iostream> #include<cstdio> #include<algorithm> #define ll long long using namespace std; int n,m; ll f[12][1<<11]; bool b[1<<11]; int main() { while(cin>>n>>m && n){ //預處理出[0,1<<m-1]中所有每一段連續的0都有偶數個的數 for(int i=0;i< 1<<m;i++){ bool cnt=0,has_odd=0;//cnt為這一段0個數的奇偶性,hasodd為是否為奇數 for(int j=0;j<m;j++) if(i>>j & 1) has_odd|=cnt,cnt=0;//第j位為1就重置,并記錄在hasodd里 else cnt^=1;//更新這一段奇偶性 b[i]=has_odd|cnt ? 0:1;//其中任何一個是1都不行 } f[0][0]=1; for(int i=1;i<=n;i++) for(int j=0;j< 1<<m;j++){//枚舉狀態 f[i][j]=0;//多組數據初始化 for(int k=0;k< 1<<m;k++) if((j&k)==0 && b[j|k]) f[i][j]+=f[i-1][k]; } printf("%lld ",f[n][0]); } }