(轮廓线dp)UVA11270-Tiling Dominoes
(轮廓线dp)UVA11270-Tiling Dominoes:
题意:
题解:
轮廓线dp.对着lrj书上的题解写的.如果将所有格子从左到右,从上到下按顺序排列,则可以dp,f[i][j][k]表示对于第i行第j列的格子前m个格子的状态为k的种类数.
那么转移有3种情况:
1.不放,必须保证当前格子上方的那一个格子不为0,否则会有空位.
2.在当前的格子和当前上方的格子摆一个骨牌.必须保证当前格子上方的那一个格子为0.
3.在当前的格子和当前左边的格子摆一个骨牌,必须保证当前格子左边的那一个格子为0,且当前格子上方的那一个格子不为0,否则会有空位.
然后初始化就是把第0个格子的(1<<m)-1设为1,因为你可以假设第0个格子的前m个格子都摆满了骨牌.
由于n,m小于等于100,则n,m至少有一个小于等于10,把n,m中较小的一个赋给m就行了.
由于lrj书上的代码用了滚动数组,所以我也用了.
还有,将i的第j为设为0,用位运算实现就是i&((1<<j)^-1),自己感受一下就知道了吧.
#include<cstdio> #include<algorithm> using namespace std; const int maxn=10; int n,m,cur; long long f[2][1<<maxn]; void clean(int d){ for(int i=0;i<(1<<m);++i) f[d][i]=0; } int main(){ for(;scanf("%d%d",&n,&m)!=EOF;){ if(n<m) swap(n,m); clean(cur); f[cur][(1<<m)-1]=1; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ clean(cur^=1); for(int k=0;k<(1<<m);++k){ if((k>>(m-1)&1)) f[cur][(k<<1)&((1<<m)^-1)]+=f[cur^1][k]; if(i!=1&&!(k>>(m-1)&1)) f[cur][(k<<1)^1]+=f[cur^1][k]; if(j!=1&&!(k&1)&&(k>>(m-1)&1)) f[cur][((k<<1)&((1<<m)^-1))^3]+=f[cur^1][k]; } } printf("%lld\n",f[cur][(1<<m)-1]); } return 0; }