这题不看题解,根本没思路。
思路如下:
对于一个矩形有3种方法:横放,竖放,不放。由于第i行只跟第i-1行的放置有关系,因为我们必须保证第i-1行使放满的,现在用dp[i][state]表示第i行
状态为state的方法,那么dp[i][now]=sum{dp[i-1][pre]}.
1 横放
如果第i行第d列我们选择横放,那么第i行的第d列及d+1列都是1了,第i-1行第d列及d+1列也都必须为1(保证是满的),及状态转移为:
d=d+2,now=now<<2|3,pre=pre<<2|3.
2竖放
第i行第d列我们选择竖放,那么第i行第d列为1,第i-1行d列必须是0,(因为我们是竖着放的,如果前一行不是空的如何能放下呢),状态转移:
d=d+1,now=now<<1|1,pre=pre<<1.
3不妨
第i行第d列不妨,那么第i-1行d列肯定是1,(保证是满的),状态转移:
d=d+1,now=now<<1,pre=pre<<1|1.
这题用递推表示真心不懂,于是记忆优化搜索一下。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> using namespace std; typedef __int64 lld; #define oo 0x3f3f3f3f #define Mod 1000000007 #define maxn (1<<11)+1 lld dp[maxn][12]; int n,m; void dfs(int r,int c,int now,int pre) { if(c==m) { dp[now][r]+=dp[pre][r-1]; return ; } //竖放 dfs(r,c+1,now<<1|1,pre<<1); //横放 if(c+2<=m) dfs(r,c+2,now<<2|3,pre<<2|3); //不放 dfs(r,c+1,now<<1,pre<<1|1); } int main() { while(scanf("%d %d",&n,&m)!=EOF) { if(n==0&&m==0) break; if(n*m&1) { puts("0"); continue; } int all=(1<<m)-1; memset(dp,0,sizeof dp); dp[all][0]=1;//0行堆满便于处理 for(int i=1;i<=n;i++) dfs(i,0,0,0); printf("%I64d\n",dp[all][n]);//最后一行堆满了就是结果了 } return 0; }