[Acwing.291] 蒙德里安的梦想(状态压缩DP复习+总结)

个人总结!!(棋盘式状态压缩DP)

0.状态压缩dp的缺点&标志

毫无疑问,指数级时间复杂度——导致棋盘的大小一般为二位数,才能用状态压缩dp求解。

1.求解此类问题

棋盘式状态压缩DP本质上是在一个棋盘内填奇奇怪怪的不同形状的块,(然后求方案数?)

2.思维难度

要能看出这是动态规划的题目,并建立状态表示,思考出状态转移。

一般来说求解该问题可以用以下几点
0.一列一列转移,
1.遍历一遍所有状态,找出所有合法状态(具体题目具体分析)。
2.二维遍历所有状态,建立状态与状态之间的转移关系(具体题目具体分析)。(这种处理方式可以大大降低运行时间!)
3.根据状态表示的实际意义,多处理一列可以直接得到答案。
4.根据状态的实际意义初始化。

3.Ac代码

写给自己看的注释

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 12,M = 1<<N;

int n,m;
ll f[N][M];
bool st[M];//是否合法
vector<int> state[M];//用于存放转移关系


void init()
{
    memset(f,0,sizeof f);
    memset(st,true,sizeof st);
}

int main()
{
    while(cin>>n>>m ,n||m)
    {
        init();//初始化
        //遍历求出合法状态
        for(int i=0;i< 1<<n;i++)
        {
            int cnt=0;//记录该段0的个数
            for(int j=0;j<n;j++)
            {
                if(i>>j & 1)//该段落结束——eg.010001
                {
                    if(cnt & 1) {st[i]=false;break;}//如果这一段0的个数是奇数,则不合法
                    cnt=0;//归零
                }
                else
                    cnt++;}
                if(cnt&1)   st[i]=false;//111000——后缀全是0这种情况
        }
        //预处理出转移关系
        for(int i=0;i< 1<<n;i++)
        {state[i].clear();
            for(int j=0;j< 1<<n;j++)
            {
                if((i & j) == 0 && st[i|j])//说明i可以转移至j。i,j可以相互转移
                    state[i].push_back(j);
            }
        }
        f[0][0]=1;//边界情况,符合状态表示的实际含义
        //开始dp
        for(int i=1;i<=m;i++)//一列一列处理,而且要多处理一列
        {
            for(int j=0;j < 1<<n;j++)//遍历所有二进制状态
            {
                for(auto k:state[j])//遍历所有能合法转移至当前j状态的状态
                {
                    f[i][j]+=f[i-1][k];//状态转移方程
                }
            }
        }
        cout<<f[m][0]<<endl;//多处理一列的意义,可以直接输出答案
    }
    return 0;
}

4.总结

之前学过的东西没有系统的整理、思考、刷例题、按知识点刷题单。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值