AC传送门:http://vjudge.net/problem/POJ-2411
【题目大意】
有一个W行H列的广场,需要用1*2小砖铺盖,小砖之间互相不能重叠,问有多少种不同的铺法?
【题解】
对于每一行有w个位置,所以每一行都有0~2w-1种状态。
对于当前行的状态s,它是由前一行的状态s’转化过来的,显然,对于该行某个位置j:
如果前一行该位置为0,那么该位置可以竖放 即 0-> 1
如果前一行连续两个位置为0,那么这两个连续位置可以横放 即00-> 00
如果前一行该位置为1,显然该位置不能再放,于是应该把该位置设置为0 ,即1-> 0
/************* poj 2411 by chty 2016.11.15 *************/ #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<ctime> #include<cmath> #include<algorithm> using namespace std; #define FILE "read" #define up(i,j,n) for(int i=j;i<=n;i++) namespace INIT{ char buf[1<<15],*fs,*ft; inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;} inline int read(){ int x=0,f=1; char ch=getc(); while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getc();} while(isdigit(ch)) {x=x*10+ch-'0'; ch=getc();} return x*f; } }using namespace INIT; int n,m; long long f[15][2500]; void dfs(int i,int s1,int s2,int next){ if(next>m) return; if(next==m) f[i+1][s2]+=f[i][s1]; else if((s2&(1<<next))==0){ dfs(i,s1,s2|(1<<next),next+1); if((s2&(1<<(next+1)))==0) dfs(i,s1,s2,next+2); } else dfs(i,s1,s2&~(1<<next),next+1); } int main(){ freopen(FILE".in","r",stdin); freopen(FILE".out","w",stdout); while(~scanf("%d%d",&n,&m)&&n&&m){ memset(f,0,sizeof(f)); f[1][0]=1; up(i,1,n) up(j,0,(1<<m)-1) if(f[i][j]) dfs(i,j,j,0); printf("%lld ",f[n+1][0]); } return 0; }