题目描述
现有n*m的一块地板,需要用1*2的砖块去铺满,中间不能留有空隙。问这样方案有多少种
输入
输入n,m(1<=n, m<=11)
有多组输入数据,以m=n=0结束
输出
输出铺砖块的方案数
样例输入
1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0
样例输出
1
0
1
2
3
5
144
51205
典型的状压dp
搜索预处理出转移
注意long long
#include<cstdio>
#define ll long long
using namespace std;
inline int read()
{
int ret=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
return ret;
}
int n,m,num;
const int N=12,S=15000;
int s1[S],s2[S];
ll f[N][S];
void dfs(int t,int a,int b)
{
if(t==m)
{
s1[++num]=a,s2[num]=b;
return;
}
if(t>m) return;
dfs(t+1,a<<1,(b<<1)+1);
dfs(t+1,(a<<1)+1,b<<1);
dfs(t+2,(a<<2)+3,(b<<2)+3);
}
int main()
{
n=read(),m=read();
while(n&&m)
{
num=0;
for(int i=0;i<=n;i++)
for(int j=0;j<(1<<m);j++) f[i][j]=0;
dfs(0,0,0);
f[0][(1<<m)-1]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=num;j++)
f[i][s2[j]]+=f[i-1][s1[j]];
printf("%lld\n",f[n][(1<<m)-1]);
n=read(),m=read();
}
return 0;
}
这是由行转移,可以改成由格子转移
* | * | * | * | * | * | ||||
* | * | * | * | & | |||||
当你要决策&的时候,你影响的只有*
像不像状压?
所以可以状压前m个格子
当你往后移的时候前面的格子也要移,那就要处理了
(保证在非(*和&和*&下面的格子)全部为1(1为有,2为空))
枚举格子O(n*m),状压前m个O(2^m)
所以时间为O(n*m*2^m)
一点都不优秀在这道题中,但是再有些题目中却如有神助
#include<cstdio>
#define ll long long
using namespace std;
inline int read()
{
int ret=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9')
ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
return ret;
}
int n,m;
const int N=13,ss=2500;
ll ans;
ll f[N][N][ss];
void dfs(int t,int S)
{
if(t==m)
{
ans+=f[n+1][1][S]; return;
}
if(t>m) return;
dfs(t+1,(S<<1)+1);
dfs(t+2,S<<2);
}
int main()
{
n=read(),m=read();
while(n&&m)
{
for(int i=1;i<=n+1;i++)
for(int j=1;j<=m;j++)
for(int S=0;S<(1<<m);S++) f[i][j][S]=0;
f[1][1][(1<<m)-1]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int S=0;S<(1<<m);S++)
if(j<m)
{
if((1<<(m-1))&S) f[i][j+1][(S-(1<<(m-1)))<<1]+=f[i][j][S];
else
{
f[i][j+1][(S<<1)|1]+=f[i][j][S];
if((1<<(m-2)&S)==0) f[i][j+1][(S|(1<<(m-2)))<<1]+=f[i][j][S];
}
} else
{
if((1<<(m-1))&S) f[i+1][1][(S-(1<<(m-1)))<<1]+=f[i][j][S];
else f[i+1][1][(S<<1)|1]+=f[i][j][S];
}
ans=0;
dfs(0,0);
printf("%lld\n",ans);
n=read(),m=read();
}
return 0;
}