(轮廓线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;
}

 

posted @ 2017-10-09 18:38  jxcakak  阅读(273)  评论(0编辑  收藏  举报