nyoj 435 状态压缩
看了大牛的博客才知道这道题是周伟《状态压缩》中的原题,搜了一下该文档,并仔细看了一下,让我茅塞顿开,原来是这样的:
令res[i][j]表示前i-1行全部铺满,第i行状态为j的方法总数(某位置有木板则为1,反之则为0);
当我们确定了第i行的状态,才能够确定第i-1行的状态。所以我们枚举第i行的所有状态就ok了。
总的来说一共有7放法:
1、 长方形木板竖放
2、 长方形木板横放
3、 缺左上角的L形木板
4、 缺右上角的L形木板
5、 缺左下角的L形木板
6、 缺右下角的L形木板
7、 不放
假如我们用dfs来遍历的话,我们可以用 i,j, s1,s2,b1, b2;分别表示当前第i行、当前第j列、i-1行状态为s1、第i行状态为s2,、本次摆放对j+1列的i和i-1行的影响。
若b1==0 && b2==0
1,2,3,4,5,6,7 可以摆放
若b1==0 && b2==1
2,3,7可以摆放
若b1==1 && b2==0
5,7 可以摆放
若b1==1 && b2==1
7可以摆放
注意:因为我们先确定i行状态,才能确定i-1行的状态,所以当我们用到i-1行时,i-1行的相应格为0(因为只有该格为0时我们此刻才能用),反之为1.
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define lld __int64
lld res[10][1024];
int m,n;
int dfs(int i,int j,int s1,int s2,int b1,int b2)
{
if(j>m)
{
if(b1==0 && b2==0) res[i][s1]+=res[i-1][s2];
return 0;
}
if(b1==0 && b2==0)
{
dfs(i,j+1,(s1<<1)+1,s2<<1,0,0);
dfs(i,j+1,(s1<<1)+1,(s2<<1)+1,1,0);
dfs(i,j+1,(s1<<1)+1,(s2<<1)+1,1,1);
dfs(i,j+1,(s1<<1)+1,s2<<1,1,0);
dfs(i,j+1,s1<<1,s2<<1,1,1);
dfs(i,j+1,(s1<<1)+1,s2<<1,0,1);
dfs(i,j+1,s1<<1,(s2<<1)+1,0,0);
}
if(b1==0 && b2==1)
{
dfs(i,j+1,(s1<<1)+1,s2<<1,1,0);
dfs(i,j+1,(s1<<1)+1,s2<<1,1,1);
dfs(i,j+1,s1<<1,s2<<1,0,0);
}
if(b1==1 && b2==0)
{
dfs(i,j+1,(s1<<1)+1,s2<<1,1,1);
dfs(i,j+1,(s1<<1)+1,(s2<<1)+1,0,0);
}
if(b1==1 && b2==1)
{
dfs(i,j+1,(s1<<1)+1,s2<<1,0,0);
}
return 0;
}
int main()
{
int i,temp;
while(scanf("%d %d",&n,&m)!=EOF)
{
if(n<m) { temp=n,n=m,m=temp;}
memset(res,0,sizeof(res));
res[0][(1<<m)-1]=1;
for(i=1;i<=n;i++) dfs(i,0,0,0,0,1);
printf("%lld\n",res[n][(1<<m)-1]);
}
return 0;
}