蒙德里安的梦想

蒙德里安的梦想

算法标签

状态压缩dp

题目大意:求把 N×M的棋盘分割成若干个1×2 的的小长方形,有多少种方案。

思路分析: 首先,注意到,我们直接考虑如何切割整个棋盘为若干个1x2的长方形是比较困难的,因此,我们可以把整个棋盘划分为若干个1x1的小格子,那么,问题就转化为了用1x2的小长方形去将整个棋盘填充满,总共有多少种方案。此外,注意到,当我们将所有横向的小长方形都已经摆放(填充)完成后,所有纵向的小长方形的摆放方式也就唯一确定了,那么,总的方案数就等于摆完所有横向长方形的方案数。所以,我们只用考虑如何枚举横向长方形的摆放即可

模型: 
这个问题属于状态压缩dp问题的第一大类:基于连通性的dp,也可以叫做棋盘式dp。我们首先考虑如何定义(设计)状态,也就是如何进行状态表示。 我们按列来枚举横向小长方形的摆放情况。f为dp数组。若当前我们需要摆放的列是第i 列,那么第i列在摆放的时候只和第i-1列有关(因为只有i-1列的小长方形可能伸到第i列,影响第i 列的摆放)。因此,我们设f[i][j]表示:前i-1列已经摆放完毕(不能再改了),当前要对第i列进行横向小长方形的摆放,且前一列伸出一个小方格是j 的情况下的方案数。如下图所示:

j是一个n位的二进制数,上图对应的j为01,代表第i-1列第0行伸出了一个小方格(所以j的第0位为1)。那么,这个状态表示的集合就是:

所有前i-1列已经摆放完毕且第i-1列伸出小方格的状态为j的情况下的摆放方案

f[i][j]记录的是集合中的方案总数(根据题目所求来确定)

接下来考虑如何进行状态计算(转移),所谓状态计算,就是对集合进行划分,而划分的依据就是“最后一个不同点”。根据我们上面f[i][j]的定义,第i-1列横向小长方形的摆放方案是确定的(因为二进制数j代表了其摆放的情况),所以,最后一个不同点就是第i-2列的摆放情况。因此,我们将依据第i-2列的摆放情况对f[i][j]所表示的大集合进行划分,将它划分成1<

2: 由于第i-1列横向的格子已经摆放完毕,那么其纵向格子的摆放方式也已经确定,所以,我们摆完横向的小长方形后,剩下连续的空格子的数量不能是奇数,否则就不能通过摆放纵向小长方形将整个棋盘填满了。所以,我们需要算出每个状态下连续0的个数。这个条件的判断可以通过”预处理完成”。

另外,我们可以预处理出所有合法(能够进行状态转移的状态),方便后续状态的计算。

这样,f[i][j]就等于所有能转移到它的状态所对应的方案数的总和。

我们最终的答案就是:f[m][0]。注意,下标从0开始,所以,它代表所有前m–1列(也就是整个棋盘)已经摆完,并且伸出格子的情况为0(没有伸出棋盘,是合法的)的方案总数。并且,dp数组的初始化为:f[0][0]=1(因为摆第0列时不存在前一列会伸出来,也就表示当前列没有横着摆的小长方形,所以只有都竖着摆放这一种情况)

c++代码

#include
#include
#include
using namespace std;
const int N=12,M=1<truestate[M];//二维数组,truestate[i]中存储所有可以转移到状态i的状态,方便通过循环递推计算出所有状态的值
//vector>truestate(M);
int main()
{
    while(cin>>n>>m,n||m) //逗号表达式的值为逗号之后的值
    {
        for(int i=0;i<1<>j&1)//i的第j位是1,前一段连续的0终止了
                {
                   if(cnt&1)//cnt为奇数
                    {
                        st[i]=0;
                        break;
                    }
                    cnt=0; //继续统计下一段连续0的个数,要将上一段的数量清零(实际上不清0也可以AC,因为加一个偶数不会影响奇偶性(奇数会break))
                }else
                    cnt++;
            if(cnt&1)//判断最后一段连续0的个数的奇偶性
                st[i]=0;
        }
        for(int i=0;i<1<

时间复杂度分析:dp问题的时间复杂度公式 =状态数量× 状态转移(计算)

状态表示 f[i][j] 第一维i可取11,第二维j(二进制数)可取2的11次方,根据乘法原理,可计算出状态数量
状态转移 也是2的11次方(每个状态最多可划分成这么多个子集)
所以总的时间复杂度约等于=4e7

你可能感兴趣的:(c++,算法,动态规划)