骨牌变形题目,加入了一些限制元素,不仅可以填充1*2规格的骨牌还可以填充1*1大小的骨牌,对于1*1的骨牌,填充数量必须在[C,D]之间才合法,
且有部分格子有花,不能填充,求在满足所有条件的情况下将所有可填充的格子填满的不同方案个数,对1e9+7取模。
显然是个经典的题目了,我的bug就是少写了一个条件和一些思路上的不足,代码写的冗余了,哎。
一是记得最高位补零,由当前状态推放置后的状态时,左移后最高位已经不在轮廓线内切记归零。
二是缜密的逻辑,对所有的情况进行不重不漏的罗列。
我先根据当前位有没有花进行分类,有花的话只有最高位为1才可进行合法转移。
无花得话表示此位置可以进行放置,分为四种情况
一、不放置,当状态最高位为1时可进行合法转移。
二、放置1*1的砖块,当状态最高位为1时可进行合法转移。
三,竖直放置1*2砖块,当行数不为0且状态最高位为0时可进行合法转移。
四,水平放置1*2砖块,当列数不为零且状态最高位为1且最低位为零时可进行合法转移。
dp[i][j][k]含义:当前处理第i个轮廓线时,状态为j,j之前的所有可填充格子全部填满,目前消耗的1*1为k个的方案数。
呼~最后记得转移时注意1*1数量最大也就是D
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 int N,M,C,D; 5 int e[105][25]; 6 LL mod=1e9+7; 7 LL dp[2][1<<10][22]; 8 void update(int cur,int pre,int now,int f1,int f2) 9 { 10 dp[cur][now][f2]=(dp[cur][now][f2]+dp[cur^1][pre][f1])%mod; 11 } 12 bool is1(int x,int y) 13 { 14 return x&(1<<y); 15 } 16 int to(int x,int y,int z) 17 { 18 if(z==1&&is1(x,y)) return x; 19 if(z==0&&(!is1(x,y))) return x; 20 if(z) return x|(1<<y); 21 if(!z) return x^(1<<y); 22 } 23 void solve() 24 { 25 memset(dp,0,sizeof(dp)); 26 int i,j,k,cur=0; 27 dp[0][(1<<M)-1][0]=1; 28 for(i=0;i<N;++i){ 29 for(j=0;j<M;++j){cur^=1; 30 memset(dp[cur],0,sizeof(dp[cur])); 31 for(k=0;k<(1<<M);++k){ 32 if(!e[i][j]){ 33 if(is1(k,M-1)) { 34 for(int t1=0;t1<=D;++t1) 35 update(cur,k,to((k<<1)|1,M,0),t1,t1); 36 } 37 } 38 else{ 39 if(is1(k,M-1)) for(int t1=0;t1<=D;++t1) update(cur,k,to((k<<1),M,0),t1,t1); 40 if(is1(k,M-1)){ //1*1 41 for(int t1=0;t1<D;++t1) 42 update(cur,k,to((k<<1)|1,M,0),t1,t1+1); 43 } 44 if(i&&(!is1(k,M-1))){ //竖着放 1*2 45 for(int t1=0;t1<=D;++t1) 46 update(cur,k,to((k<<1)|1,M,0),t1,t1); 47 } 48 if(j&&(is1(k,M-1))&&(!is1(k,0))){ 49 for(int t1=0;t1<=D;++t1) 50 update(cur,k,to((k<<1)^3,M,0),t1,t1); 51 52 } 53 54 } 55 } 56 } 57 }LL ans=0; 58 for(int i=C;i<=D;++i) ans=(ans+dp[cur][(1<<M)-1][i])%mod; 59 cout<<ans<<endl; 60 } 61 int main() 62 { 63 int i,j; char c; 64 while(cin>>N>>M>>C>>D){ 65 for(i=0;i<N;++i){ 66 for(j=0;j<M;++j){cin>>c; 67 e[i][j]=c-'0'; 68 } 69 } 70 solve(); 71 } 72 return 0; 73 }