题意:给出一个N*M的矩形,用许多的1*2的小方块,把大矩形填满的方式有多少种。
网址:http://poj.org/problem?id=2411
解法 1:在位中1表示横着的,0表示竖着的下面一位。
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int n,m;
int Next;
int next[14000][2];
long long dp[12][1<<11];
void dfs(int len,int from,int to)
{
if (len>m)
return;
if (len==m)
{
next[Next][0]=from;
next[Next++][1]=to;
return;
}
dfs(len+2,(from<<2)+3,(to<<2)+3);
dfs(len+1,(from<<1)+1,to<<1);
dfs(len+1,from<<1,(to<<1)+1);
}
int main()
{
freopen("in","r",stdin);
int i,j,k;
while (cin>>n>>m,n&&m)
{
if (n<m)
swap(n,m);
Next=0;
dfs(0,0,0);
memset(dp,0,sizeof(dp));
dp[0][(1<<m)-1]=1;
for (i=0;i<n;i++)
for (j=0;j<Next;j++)
dp[i+1][next[j][1]]+=dp[i][next[j][0]];
cout<<dp[n][(1<<m)-1]<<endl;
}
return 0;
}
解法2:
用2进制的01表示不放还是放 第i行只和i-1行有关 枚举i-1行的每个状态,推出由此状态能达到的i行状态 如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态。 然后用搜索扫一道在i行放横着的方块的所有可能,并且把这些状态累加上i-1的出发状态的方法数,如果该方法数为0,直接continue。 举个例子 2 4 1111 1111 状态可以由 1100 0000 0110 0011 1111 0000 0000 0000 0000 0000 这五种i-1的状态达到,故2 4 的答案为5
#include<cstdio> #include<cstring> long long f[30][1<<12],i,j,n,m,saya=1; void sayatime (int i,int s1,int pos) { if (pos==m) {f[i][s1]+=saya;return;} sayatime(i,s1,pos+1); if (pos<=m-2&&!(s1&1<<pos)&&!(s1&1<<pos+1)) sayatime(i,s1|1<<pos|1<<pos+1,pos+2); } int main() { while(scanf("%d%d",&n,&m),n!=0) { memset(f,0,sizeof(f));saya=1; sayatime(1,0,0); for (i=2;i<=n;i++) for (j=0;j<1<<m;j++) { if (f[i-1][j]) saya=f[i-1][j]; else continue; sayatime(i,~j&((1<<m)-1),0); } printf("%lld\n",f[n][(1<<m)-1]); } }