Mondriaan's Dream POJ - 2411(状压dp)
这里是链接(^_−)☆
dp[i][j]表示第i行状态为j时的方案数
在位置(i, j) 如果我们选择横着贴砖,那么将(i, j), (i, j+1)都填写成1,如果竖着贴砖,我们将(i,j)填写成0,将(i+1, j)填写成1.
及0是对下一行的状态有影响,1为没有
枚举每一种状态 判断合法性
剪枝:如果上一行的状态数为0,直接continue
//#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<queue> #include<set> #include<map> #include<vector> #define inf 0x3f3f3f3f #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long #define sd(x) scanf("%d",&(x)) #define sl(x) scanf("%lld",&(x)) #define slf(x) scanf("%lf",&(x)) #define scs(s) scanf("%s",s) #define rep(i,a,b) for(int i=a;i<=b;i++) #define per(i,a,b) for(int i=a;i>=b;i--) #define lowbit(x) x&(-x) #define ls now<<1 #define rs now<<1|1 #define lson l,mid,ls #define rson mid+1,r,rs #define All L,R #define int long long using namespace std; const int maxn=1e4+10; int n,m; long long dp[15][3005]; int Cheek(int now) { int i=0; while(i<m) { if((now&(1<<i))==0)i++; else if(i==m-1||!(now&(1<<(i+1))))return 0; else i+=2; } return 1; } int cheek(int a,int b) { int i=0; while(i<m) { if((a&(1<<i))==0) { if((b&(1<<i))==0) return 0; else i++; } else { if((b&(1<<i))==0) i++; else if(i==m-1||!((a & (1<<(i+1)))&&(b&(1<<(i+1))))) return 0; else i+=2; } // cout<<i<<endl; } return 1; } /*** !(((a&(1<<(i+1)))==1) && ((b&(1<<(i+1)))==1)) !((a&(1<<(i+1))) && (b&(1<<(i+1)))) if((b & (1<<i)) == 0) i++; else if(i == m-1 || !((a &(1<<(i+1))) && (b &(1<<(i+1))))) { return 0; } else i += 2; ***/ #undef int int main() { #define int long long while(~scanf("%lld%lld",&n,&m)) { if(!n&&!m) return 0; if(m>n) swap(n,m); int M=(1<<m)-1; mem(dp,0); rep(i,0,M) if(Cheek(i)) dp[0][i]=1; rep(i,1,n-1) { rep(j,0,M) { rep(k,0,M) { if(!dp[i-1][j]) continue; if(cheek(j,k)) dp[i][k]+=dp[i-1][j]; } } } rep(i,0,n-1) { rep(j,0,M) cout<<dp[i][j]<<" "; cout<<endl; } cout<<dp[n-1][(1<<m)-1]<<"\n"; } return 0; }