用1*2的矩形填满M*N的矩形有多少种方案(状态压缩dp)

代码仿照自:https://fanfansann.blog.youkuaiyun.com/article/details/108298578
用二进制代表每一行的状态,如100001
其中:
0代表小方块横着放或者这一行和上一行有竖着放的小方块
1代表这一行和下一行有竖着放的小方块

遍历每一行,第i行只与第i-1行有关,第i - 1行的状态k能转移到第i行的状态j,当且仅当

1、 j & k == 0, 即第i列和第i - 1列的每一行都没有连续两个横向棋子重叠放置

2、 flag[j | k] == true 即第i列和第i - 1列合并以后(要合并是因为第i列和第i - 1列都是两个空格子才行,一列有竖棋子的上半部分一列没有是不算的)的状态没有出现连续空格子为奇数个

public class Solution {
    //0代表小方块横着放或者这一行和上一行有竖着放的小方块
    //1代表这一行和下一行有竖着放的小方块
    public  static long StateCompressionDP(int high,int length)
    {
        //保证length不大于high
        if(length>high)return StateCompressionDP(length,high);
        //如果面积是奇数的话那就没救了
        if(((high*length)&1)==1)return 0;
        //一行一行来,每行填满之后才能填下一行,一行有length列
        //每列有0或者1两种状态,所以一共有1<<length种状态//dp[i][j]代表
        //有dp[i][j]种路径使第i行变成第j种状态
        long[][]dp=new long[high][1<<length];
        // flag[i]=true代表第1行的第i种状态可行
        boolean[] flag=new boolean[1<<length];
        //首先初始化第0行的状态
        for(int i=0;i<flag.length;i++)
        {
            flag[i]=true;
            //count计算0的个数,因为只需要知道是奇数还是偶数所以可以一直加
            int count=0;
            //k是第i种状态的二进制表现形式
            int k=i;
            for(int j=0;j<length;j++)
            {
                //遇到了1说明连续的0被截断了
                if((k&1)==1)
                {
                    //此时连续0的个数是奇数个
                    if((count&1)==1) {
                        flag[i] = false;
                        break;
                    }
                }
                //遇到了0
                else
                {
                    count++;
                }
                k>>=1;
            }
            //如果此时0的个数是奇数个也不合法
            if((count&1)==1)flag[i]=false;
            //第0行可行的就令dp[0][i]为1
            dp[0][i]=flag[i]==true?1:0;
        }



        //i遍历的是每一行,i从1开始是因为第0行初始化好了
        for(int i=1;i<dp.length;i++)
            //j遍历的是第i行的所有状态
            for(int j=0;j<dp[0].length;j++)
                //k遍历的是第i-1行的所有状态
                for(int k=0;k<dp[0].length;k++)
                {
                    // 若第i-1行的状态x和第i行的状态y满足flag[x|y]==false则代表不可行,因为第一行只
                    //判断了连续的0是否是偶数个,而flag[x|y]==false代表了i-1与i行连续n列都是0的n为奇数
                    //两行的某一列都是1是不允许的,详情看定义
                    if((j&k)==0&&flag[j|k])
                    {
                        dp[i][j] += dp[i - 1][k];
                    }
                }
        //为什么只返回dp[high-1][0]呢?因为最后一行必须全0,如果有1意味着需要下一行
        return dp[high-1][0];
    }

    public static void main(String[] args) {
        int length=5;
        int high=8;
        System.out.println(StateCompressionDP(length, high));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值