LightOJ 1270 Tiles (II)(状态压缩)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1270

题意:用六种形状的砖铺满给定的n*m的格子的方案总数。

思路:对于给定的m(m<=n),预处理出铺满每个状态[0,(1<<m)-1]下一行的形状,然后一行一行的DP即可。。。

#include <stdio.h>

#include <string.h>

#include <vector>

#define i64 unsigned long long

#define min(x,y) ((x)<(y)?(x):(y))

using namespace std;



int C,num=0;

int a[105][10],n,m;

char s[105][105];

i64 f[105][1<<8];

vector<int> V[260];



void DFS(int st,int p,int t)

{

    if(p==m)

    {

        V[st].push_back(t);

        return;

    }



    if(st&(1<<p))

    {

        DFS(st,p+1,t);

        return;

    }

    int t0;

    if(!(t&(1<<p)))

    {

        t0=t|(1<<p);

        DFS(st,p+1,t0);

    }

    if(p+1<m&&!(st&(1<<(p+1))))

    {

        t0=t;

        DFS(st,p+2,t0);

    }

    if(p+1<m&&!(t&(1<<p))&&!(t&(1<<(p+1))))

    {

        t0=t|(1<<p)|(1<<(p+1));

        DFS(st,p+1,t0);

    }

    if(p+1<m&&!(t&(1<<p))&&!(st&(1<<(p+1))))

    {

        t0=t|(1<<p);

        DFS(st,p+2,t0);

    }

    if(p-1>=0&&!(t&(1<<(p-1)))&&!(t&(1<<p)))

    {

        t0=t|(1<<(p-1))|(1<<p);

        DFS(st,p+1,t0);

    }

    if(p+1<m&&!(t&(1<<(p+1)))&&!(st&(1<<(p+1))))

    {

        t0=t|(1<<(p+1));

        DFS(st,p+2,t0);

    }

}



void init()

{

    int i,j;

    if(m<=n)

    {

        for(i=0;i<n;i++) for(j=0;j<m;j++) a[i][j]=s[i][j]=='#';

    }

    else

    {

        for(i=0;i<m;i++) for(j=0;j<n;j++) a[i][j]=s[j][i]=='#';

        i=n;n=m;m=i;

    }

    for(i=0;i<(1<<m);i++) V[i].clear();

    for(i=0;i<(1<<m);i++)

    {

        DFS(i,0,0);

    }

}



int get(int r)

{

    int st=0,i;

    for(i=0;i<m;i++) st=((st<<1)|a[r][i]);

    return st;

}







i64 DP()

{

    if(n==1) return 0;

    int i,j,k,t,st=get(0);

    memset(f,0,sizeof(f));

    j=get(1);

    for(i=0;i<V[st].size();i++)

    {

        k=V[st][i];

        if(!(k&j)) f[1][k|j]++;

    }

    for(i=1;i<n;i++) for(k=get(i+1),j=0;j<(1<<m);j++)

    {

        for(t=0;t<V[j].size();t++)

        {

            st=V[j][t];

            if(i==n-1)

            {

                if(!st&&j!=(1<<m)-1)

                    f[i][(1<<m)-1]+=f[i][j];

            }

            else

            {

                if(k&st) continue;

                f[i+1][k|st]+=f[i][j];

            }

        }

    }

    return f[n-1][(1<<m)-1];

}



int main()

{

    for(scanf("%d",&C);C--;)

    {

        scanf("%d%d",&n,&m);

        int i;

        for(i=0;i<n;i++) scanf("%s",s[i]);

        init();

        printf("Case %d: %llu\n",++num,DP());

    }

    return 0;

}

  

 

 

你可能感兴趣的:(tiles)