zoj 1100 铺砖 状态压缩

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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值