状态压缩DP

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 复习acwing算法基础课的内容,本篇为讲解基础算法:动态规划——状态压缩DP,关于时间复杂度:目前博主不太会计算,先鸽了,日后一定补上。

文章目录

前言

一、动态规划

二、例题,代码

AcWing 291. 蒙德里安的梦想

本题解析

AC代码

AcWing 91. 最短Hamilton路径

本题解析

AC代码

三、时间复杂度


前言

复习acwing算法基础课的内容,本篇为讲解基础算法:动态规划——状态压缩DP,关于时间复杂度:目前博主不太会计算,先鸽了,日后一定补上。


一、动态规划

动态规划(Dynamic Programming,DP)是求解决策过程最优化的过程,个人认为是目前接触的所有算法里最绕的…


这里的题目的解题方法来自于:y总的闫氏dp分析法


二、例题,代码

AcWing 291. 蒙德里安的梦想

本题链接:AcWing 291. 蒙德里安的梦想

本博客提供本题截图:

image.png

image.png

本题解析

image.png

我们只需要把横向的方块选择好后,竖向的方块只有一种情况,故我们所求情况数为我们横向的方块的填放方案数,比如在上图中的蓝色大方格中,我们只需要填好横向的格子:红色的格子,那么其他剩下的即为竖向的格子,只有一种填写方法。


合法化:如果我们填好了横着的小方块,其余剩下的部分可以由竖着的小方块填充满的话则证明该方案合法:按列去看,每一列内部的所有连续空着的小方格的个数需要是偶数

image.png


其余解释在代码中解释

AC代码

#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 12, M = 1 << N;
int n, m;
LL f[N][M];            // 第一维表示列, 第二维表示所有可能的状态,注意要用long long 否则会爆int
vector<int> state[M];
bool st[M];           //存储每种状态是否有奇数个连续的0,奇数为false,偶数为true
int main()
{
    while (cin >> n >> m, n || m)
    {
        //预处理1:利用连续未填格子的奇偶数去筛掉一些情况
        for (int i = 0; i < 1 << n; i ++ )
        {
            int cnt = 0;        //记录连续的0的个数
            bool is_valid = true;
            for (int j = 0; j < n; j ++ )
                if (i >> j & 1)       //如果是 i >> j == 1进入if
                {
                    if (cnt & 1)    //如果cnt是奇数
                    {
                        is_valid = false;
                        break;
                    }
                }
                else cnt ++ ;     
            if (cnt & 1) is_valid = false;    //判断最下面的那一段0的个数
            st[i] = is_valid;
        }
    //预处理2:看第i-2列伸出来的和第i-1列伸出去的是否冲突
        for (int i = 0; i < 1 << n; i ++ )    //对于第i列的所有情况
        {
            state[i].clear();                 //因为有多组输入,故每次操作要清空
            for (int j = 0; j < 1 << n; j ++ )//对于第i - 1列的所有情况
                if ((i & j) == 0 && st[i | j])// j|k 就是第 i-1 列的有几个1,即哪几行是横着放格子的
                    state[i].push_back(j);    //把合法的情况放入数组之中
        }
    //dp:
        memset(f, 0, sizeof f);    //多组输入数据,每次清空
        f[0][0] = 1;
        //按照定义,上一行中的代码指的是已经将前-1列摆好,且从-1列伸出到第0列的方案数为1   (类似空集)
        for (int i = 1; i <= m; i ++ )   //遍历每一列
            for (int j = 0; j < 1 << n; j ++ ) //遍历每一列的所有状态
                for (auto k : state[j])
                    f[i][j] += f[i - 1][k]; //当前列的方案数就等于之前的第 i-1 列所有状态k的和
        cout << f[m][0] << endl;
        //f[m][0]表示 前 m-1 列都处理完,并且第m-1列没有伸出来的所有方案数
    }
    return 0;
}

AcWing 91. 最短Hamilton路径

本题链接:AcWing 91. 最短Hamilton路径

本博客提供本题截图:

image.png

本题解析

image.png

具体解释与代码中讲解

AC代码

#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 20, M = 1 << N;
int n;
int w[N][N];
int f[M][N];
int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < n; j ++ )
            cin >> w[i][j];
    memset(f, 0x3f, sizeof f);
    f[1][0] = 0;    //从0出发,经过的点集为1,即到达0这个点,即为0到0
    for (int i = 0; i < 1 << n; i ++ )  //开始枚举所有的情况
        for (int j = 0; j < n; j ++ )   //枚举到达的所有的点
            if (i >> j & 1)             //如果当前的点的集合包括点 j ,进行状态转移
                for (int k = 0; k < n; k ++ )   //枚举从哪一个点转移过来
                    if ((i - (1 << j)) >> k & 1) //去掉点 j 后,仍然包含 k
                        f[i][j] = min(f[i][j], f[i - (1 << j)][k] + w[k][j]);
    cout << f[(1 << n) - 1][n - 1];   //最终输出 f[111...111][n - 1]
    return 0;
}

三、时间复杂度

关于动态规划——状态压缩DP的时间复杂度以及证明,后续会给出详细的说明以及证明过程,目前先鸽了。

目录
相关文章
|
2月前
|
消息中间件 Kubernetes NoSQL
动态规划-状态压缩、树形DP问题总结
动态规划-状态压缩、树形DP问题总结
【动态规划】198. 打家劫舍
【动态规划】198. 打家劫舍
|
2月前
树形dp之没有上司的舞会
树形dp之没有上司的舞会
|
2月前
动态规划记忆化搜索之滑雪
动态规划记忆化搜索之滑雪
|
2月前
|
存储 人工智能 BI
树形dp总结
树形dp总结
28 0
|
9月前
poj 1185 炮兵阵地 (状态压缩dp)
如果你是刚刚开始做状态压缩dp,我建议你先看看 poj 3254 Corn Fields 这是一道比这一题更简单,更容易入门的题目。 还有在代码中我用了一个很巧妙的方法求一个数二进制数中1的个数 具体请看我博客中 x& (x - 1)==0 这篇文章 链接 。
23 1
|
9月前
|
算法
【学会动态规划】打家劫舍 II(12)
【学会动态规划】打家劫舍 II(12)
15 0
|
12月前
|
存储 Cloud Native Go
198. 打家劫舍:动态规划
这是 力扣上的 198. 打家劫舍,难度为 中等。
|
12月前
|
Go Cloud Native
213. 打家劫舍 II:动态规划
这是 力扣上的 213. 打家劫舍 II,难度为 中等。
|
12月前
|
机器学习/深度学习 Cloud Native Go
337.打家劫舍 III:动态规划
这是力扣上的 337. 打家劫舍 III,难度为 中等。