zoj 1100 铺砖 状态压缩

来源:互联网 发布:月目标计算法 编辑:程序博客网 时间:2024/06/05 20:44

1、st中存的是每一行摆放的所有可能,0是空着,1是占着,st[i][0]中存一行的可能的状态即from,st[i][1]中存与其匹配的下一行状态即to;

2、dfs中from是一行中前n个格子的状态,to是与之吻合的状态;

3、因为只看每一行的可能状态,所以dfs中的n==w时已取完该种可能,退出递归;

4、对于一行的第n列,采取三种摆放长方形的方式

dfs(n+2,(from<<2)+3,(to<<2)+3); //横着放,这层和下一层匹配的都多两位1  (二进制11就是3嘛)
dfs(n+1,(from<<1)+1,to<<1);//竖着放,这层多一个1,匹配下层这个位置是0
dfs(n+1,from<<1,(to<<1)+1);//不放,这层多一个0,匹配的下层多个1

5、dp[i][j]中存第i行摆放状态为j时的方法数,边界是要全放满的,dp[0][(1<<w)-1]=1,最后要求的是dp[h][(1<<w)-1];

6、dp过程是

for(i=1;i<=h;i++)
{
        for(j=0;j<cnt;j++)
        {
               dp[i][st[j][1]]+=dp[i-1][st[j][0]];
       }

}

#include<stdio.h>#include<string.h>int st[3000][2];int dp[11][3000]; //2^11=2048最多的状态数int cnt,h,w;void dfs(int n,int from,int to)//枚举所有一行摆放的可能和其匹配的下层{    if(n>w)        return;    if(n==w)  //这一行刚好摆完,得到一行摆放的组合    {        st[cnt][0]=from;        st[cnt][1]=to;        cnt++;        return;    }    dfs(n+2,(from<<2)+3,(to<<2)+3); //横着放,这层和下一层匹配的都多两位1    dfs(n+1,(from<<1)+1,to<<1);//竖着放,这层多一个1,匹配下层这个位置是0    dfs(n+1,from<<1,(to<<1)+1);//不放,这层多一个0,匹配的下层多个1}int main(){    int i,j;    while(scanf("%d %d",&h,&w)&&h)    {        if((w*h)%2)        {            printf("0\n");            continue;        }        memset(dp,0,sizeof(dp));        memset(st,0,sizeof(st));        cnt=0; //记录每一行摆放所有可能的状态总数        dfs(0,0,0);        dp[0][(1<<w)-1]=1;//边界        for(i=1;i<=h;i++)        {            for(j=0;j<cnt;j++)            {                dp[i][st[j][1]]+=dp[i-1][st[j][0]];            }        }        printf("%d\n",dp[h][(1<<w)-1]);    }    return 0;}