• 清北学堂2019.7.17


    Day 5 钟皓曦(这里就不得不安利一下之前上的钟神的dp课程了【屠龙宝刀点击就送】)

    Dp(动态规划)
    斐波那契数列->

      1.用别人算自己,复杂度O(n)

      2.用自己算别人,复杂度O(n)

      3.运用记忆化搜索
    会存在一些题,几种代码的难度差别很大
    无后效性:动态规划所有状态之间组成了一个有向无环图

         如果会乱序,那么拓扑排序,之后for一边
    状态:所算的东西
    转移方程:算的方法
    《背包九讲》
    一。背包dp
    n个物品,m个容器,每个物品都其体积与价值,求最大的价值
    (01背包)
    经典问题:采药

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iomanip>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    int dp[10000000],v[1000],p[1000];
    int main()
    {
        int n,m;
        cin>>n>>m;
        for(int a=1;a<=m;a++)
        {
            cin>>v[a]>>p[a];
        }
        for(int j=1;j<=m;j++)
        {
            for(int i=n;i>=v[j];i--)
            {
                    dp[i]=max(dp[i],dp[i-v[j]]+p[j]);
            }
        }
        cout<<dp[n];
        return 0;
    }

    转移方程:f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i])(前提j>=v[i])
    在最后的时候,还要用ans=0再来更新一边答案,保证答案正确

    (完全背包)
    经典问题:疯狂采药

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iomanip>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    int dp[10000000],v[10001],p[10001];
    int main()
    {
        int n,m;
        cin>>n>>m;
        for(int a=1;a<=m;a++)
        {
            cin>>v[a]>>p[a];
        }
        for(int j=1;j<=m;j++)
        {
            for(int i=v[j];i<=n;i++)
            {
                    dp[i]=max(dp[i],dp[i-v[j]]+p[j]);
            }
        }
        cout<<dp[n];
        return 0;
    }


    (有限背包)
    把多个物品转化成捆绑包,则问题转化成了01背包

    这里并没有找到切实际的题目,还是看背包九讲吧qwq
    二。基础dp
    经典例题:数字三角形

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int f[1001][1001],a[1001][1001],n;
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
             cin>>a[i][j];
        }
        f[1][1]=a[1][1];
        for(int i=2;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            f[i][j]=max(f[i-1][j-1],f[i-1][j])+a[i][j];
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            ans=max(ans,f[n][i]);
        }
        cout<<ans;
        return 0;
        }

    数字三角形2(思路↓)
    f[i][j][k]走到第i行第j列mod100==k是否成立【bool型】
    最长不上升子序列:可以用线段树加以优化


    三。区间dp
    经典例题:石子合并(这种问题一看就是区间dp【算是一种区间dp的应用】)
    f[l][r]=min(f[l][p]+f[p+1][r]+sum[r]-sum[l-1])【l<=p<r】
    问题:矩阵乘法,自定义顺序,是的运算次数最少
    f[l][r]表示把第l个矩阵到第r个矩阵合并成一个矩阵所用的最少次数
    同样枚举分界点
     f[j][i]=min(f[j][i],f[j][k]+f[k+1][i]+a[j]*a[k+1]*a[i+1])


    四。状压dp
    平面上有n个点,第i个点的坐标为(x[i],y[i]),要求从一号点出发,把所有点都走一遍之后回到一号点,求解最短的一条路径
    f[s][i]表示在i边走过了s个点
    状压:将数字代表数组:经过哪个点,对应二进制为1,反之为0。
    代码8(TSP旅行商P1171)    


    洛谷P1879
    农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地。John打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
    遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
    John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
    f[i][s]前i行的草已经行种成s样(种成什么模样)也是压缩成一个单独的状态【二进制位上不能有连续的两个1】
    五。数位dp
    f[i][j]表示已经从最高位向低位填了i为,j=0表示填的数小于x,j=1表示刚好等于x
    枚举下一位填什么
    一般会把[l,r]看成[0,r]-[0,l-1]
    数位dp枚举位数的复杂度大概是O(log n)
    求在[L,R]中的数的数位之和
    思路:f[i][j]表示做到第i位是否顶上界的数位之和
    求解:[l,r]中有多少个相邻两数之差至少为2的数?
    多加一个维度
    f[i][j][k]:已经填到了第i位,j表示前面的是小于还是等于,k表示第i位为k
    windy 数(选做)
    求在[L,R]中的满足各位数字之积为K的数有多少个                      L,R <=10^18
    用六维dp:f[i][j][a][b][c][d] a表示2的幂数 b表示3的幂数 c表示5的幂数 d表示7的幂数
    bzoj 2757 Blinker的仰慕者
    但是还需要优化qwq
    找出仅以2,3,5,7为因子的数,打表(搜索)然后降维
    f[i][j][k]k表示第k个这样的数
    六。树形dp(有根树才能跑)
    求树上有多少个点
    求树的直径
    从LCA的最长和次长
    f[i][0]表示从i向下走,最长走多少,f[i][1]表示从i向下走,次长走多少
    求树上路径总长度和
    f[i]表示以i为根的子树有多少个点
    Σ2*f[i]*(n-f[i])
    P1352 没有上司的舞会
    f[i][j] j=0没选 j=1选了
    max(f[1][0],f[1][1])
    若i选了,则i的儿子都不能选
    f[i][1]=Σ(f[j][0])+v[i]       j∈son[i]
    f[i][0]=Σmax(f[j][0],f[j][1]) j∈son[i]
    洛谷P2016
    f[i][0]=Σ(f[j][0])+v[i]       j∈son[i]
    f[i][1]=Σmax(f[j][0],f[j][1]) j∈son[i]
    如果守护结点不能距离超过二(消防局的设立)
    f[i][j] j表示在i这棵子树被完全的情况下,往下走走到的最近的士兵的距离
    f[i][0]=Σmin(f[j][0/1/2])+1   j∈son[i]
    g[j][0/1] j 表示已经确定了前j个儿子的取值 0/1表示有没有一个儿子有士兵
    f[i][1] 还需要再套一个dp
    f[i][2] zhx咕咕咕

  • 相关阅读:
    【设计模式】模板模式
    【设计模式】适配器模式
    【设计模式】观察者模式
    【设计模式】原型模式
    【设计模式】建造模式
    【Android Studio】Android Studio 安装及设置
    【设计模式】工厂模式(静态工厂模式、工厂方法模式、抽象工厂模式)
    【Linux高级驱动】LCD logo
    【Linux高级驱动】LCD驱动框架分析
    【系统移植】JNI
  • 原文地址:https://www.cnblogs.com/gongcheng456/p/11202896.html
Copyright © 2020-2023  润新知