zoukankan      html  css  js  c++  java
  • 经典DP

    1.背包问题

    (1)01背包

    从n个重量和价值分别为wi,vi的物品,从中选出不超过W的物品,每种物品仅有一件,求所有方案中V的最大值。

    最朴素最简单也最费时的方法:O(2^n) int rec(int i,int j)//从第i个开始挑选总重小于j的部分

    递归  递归终止条件:i==n  return 0;

          递归分支:① j<wi res=rec(i+1,j);  //无法挑选,看下一个

                    ② res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]))//挑选,不挑选,选其中大的

    分析:递归搜索深度→n,每层两次分支(选与不选),有重复计算

    优化:记录每次递归的结果(记忆化搜索)

     

    Int dp[MAX_N][MAX_N];

    递归 int rec(int i,int j)

        初始条件:memset(dp,-1,sizeof(dp));

    终止条件:①dp[i][j]>=0 returndp[i][j]//已计算过

    ②i==n return 0;

        递归分支:① j<wi res=rec(i+1,j);  //无法挑选,看下一个

                    ② res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]))//挑选,不挑选,选其中大的

    分析及remark:复杂度O(nW)

       数组初始化:①memset(type *arrary,figure,sizeof(arrary))

                          只能填充(0,+-1,0x3f3f3f3f),其他值不可以 

                          memset按照1字节为单位对内存填充,-1的二进制每一位均为1

                          ②fill(type* arrary,type *arrary+n,figure) 可赋值任意值

        递归  

     ↓↓↓↓↓↓                  for(int i=n-1;i>=0;i--) //

    递推(双重循环)           for(int j=0;j<=w;j++)

                              { if(j<w[i]) dp[i][j]=dp[i+1][j]; //不选

                             else dp[i][j]=max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);}

    其他3种递推写法:(来源:《挑战程序设计竞赛》)

     

    (2)完全背包

    递推关系1:(3重循环,有重复计算)复杂度O(nW^2)

    For(int i=0;i<n;i++)

     For(int j=0;j<=w;j++)

      For(int k=0;k*w[i]<=j;k++)

      Dp[i+1][j]=max(dp[i+1][j],dp[i+1][j-k*w[i]]+k*v[i])

    优化:(左上→右下  变为 左→右)

    Dp数组初始化为0

    For(int i=0;i<n;i++)

     For(int j=0;j<=w;j++)

    {

     If(j<w[i]) dp[i+1][j]=dp[i][j];

     Else  dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i])

    }           只有这里与01背包不同,前j个已更新过,可直接用

     

    进一步优化:用一个数组实现,只需要记录当前最优状态

    比较01背包与完全背包(循环方向不同)

     

    2.LCS(Longest common subsequence)

     

    dp[n][m]即为所求

    for(int i=0;i<n;i++)

      for(int j=0;j<m;j++)

    {

      if(s[i]==t[i])

       dp[i+1][j+1]=dp[i][j]+1;

    else

       dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1])

    }

     

    3.LIS(Longest Increasing subsequence)

     

    dp[i]:以ai为结尾的最长上升子序列长度

    dp[i]=max{1,dp[i]+1|j<i且aj<ai}

    O(n^2)

    int res;

    for(int i=0;i<n;i++)

     {

      dp[i]=1;

    for(int j=0;j<i;j++)

      if(a[j]<a[i])              //每存在aj<ai&&j<i,dp[i]更新一次

       dp[i]=max{dp[i],dp[j]+1};

    }

    res=max{dp[i]|0<=i<n}

    Remark:

    其他方法:

    可以用lower_bound();

       dp[i]:长度为i+1的上升子列中末尾元素的最小值(不存在的话为inf)

    dp[max_n]初始化为inf,按顺序逐个考虑数列的元素,对于每个ai,如果i=0||dp[i-1]<ai,就用dp[i]=min(dp[i],ai)更新,最终找出使得dp[i]<inf的最大的i+1即为结果。DP直接实现,可以在O(n^2)的时间内给出结果,但可以进一步优化,dp数组中除inf之外是单调递增的,对于每个ai最多有一次更新,更新的位置可用二分的方法优化,时间复杂度可以降低到O(nlogn)

    int dp[max_n]

    void solve()

    {

      fill(dp,dp+n,inf);

      for(int i=0;i<n;i++)

        *lower_bound(dp,dp+n,a[i])=a[i];

      res=lower_bound(dp,dp+n,inf)-dp;

    }

    // lower_bound()可以从已排好序的a中利用二分搜索找出满足ai>=k的ai的最小的指针,类似的还有upper_bound,找出的为ai>k的最小指针

    //求n个有序数组a中k的个数,可以用:upper_bound(a,a+n,k)-lower_bound(a,a+n,k);

  • 相关阅读:
    客户主数据批导
    update module (更新模块)
    关于SAP的编码范围
    MV45AOZZ 销售订单增强点
    BAPI list
    sap crm 常用表
    ME01 创建货源清单
    SAP采购寄售业务操作步骤
    让APK 成功在 Windows 运行并可以设置本地文件
    FastAdmin 学习线路 (2018-06-09 更新)
  • 原文地址:https://www.cnblogs.com/Egoist-/p/7391224.html
Copyright © 2011-2022 走看看