【動態規劃——狀態壓縮】dream——蒙德里安的夢
阿新 • • 發佈:2019-02-15
用二進位制狀態壓縮,用f[i][s]表示做到第i行狀態為s。
s的二進位制表示第幾位(第幾個位置)是否被放過——狀態s=10(1010)第一個位置被放過,第二個位置沒被放過,第三個位置被放過,第四個位置沒被放過。
然後分層列舉本層狀態與上層狀態,若兩種狀態相符合,f[i][s]+=f[i-1][ss](ss為上層狀態,s為本層狀態)。
判斷狀態符合方法:
1、s中j位為0,ss中j位為1(在i位豎著放,放在i-1行和i行)
2、s中j位為0,ss中j位為0(狀態不符合)
3、s中j位為1,ss中j位為0(不放,之後在i+1行更新)
4、s中j位為1,ss中j位為1;s中j+1位為1,ss中j+1位為1(橫著放)
5、s中j位為1,ss中j位為1;s中j+1位不為1,或ss中j+1位不為1(狀態不符合)
在此之前提前處理第一行,只能橫著放。
#include<cstdio> #include<cstring> int n,m; long long f[21][5001]; int maxs=0; bool check(int s,int ss) { for(int i=0;i<m;) { if(s&(1<<i)) { if(ss&(1<<i)) { if(i==(m-1)||(s&(1<<(i+1)))==0||(ss&(1<<(i+1)))==0) { return 0; } else { i+=2; } } else { i++; } } else { if(ss&(1<<i)) { i++; } else { return 0; } } } return 1; } void solve() { for(int i=2;i<=n;i++) { for(int syh=0;syh<=maxs;syh++) { for(int zyh=0;zyh<=maxs;zyh++) { if(check(syh,zyh)) { f[i][zyh]+=f[i-1][syh]; } } } } } void cl1(int s,int u) { int cl; if(s==maxs) { return; } for(int i=u;i<m;i++) { cl=s; cl|=(1<<i); cl|=(1<<(i+1)); f[1][cl]=1; cl1(cl,i+2); } } int main() { // freopen("dream.in","r",stdin); // freopen("dream.out","w",stdout); memset(f,0,sizeof(f)); scanf("%d %d",&n,&m); if(n%2==1&&m%2==1) { printf("0"); return 0; } int ji=1; for(int i=0;i<m;i++) { maxs+=ji; ji*=2; } f[1][0]=1; cl1(0,0); solve(); printf("%lld",f[n][maxs]); return 0; }