• 动态规划


    一.特性:

        (1)最优子结构性质。即问题的最优解所包含的子问题的解也是最优的。

        (2)子问题重叠性质。在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,

    有些子问题会被重复计算多次,利用子问题的重叠性质,对于每个子问题只计算一次,然后将结果保存

    起来,下次需要重新计算已经计算过的的问题查询结果即可。

        (3)无后效性:每个状态都是过去历史的一个完整总结。

    二.Dp分类

        简单的Dp:

            (1)递推:一般形式单一,从前往后分类枚举即可。

            (2)背包:0-1背包、完全背包、分组背包、多重背包

            (3)LIS:最长递增子序列,朴素的LIS是复杂度为O(n2)的算法,二分下的LIS是复杂度O(nlog2n)的算法。

            (4)LCS:最长公共子序列,通常时间复杂度为O(n2)的算法

        区间Dp:

            枚举将区间分成左右两部分,然后求出左右区间再合并。

        树形Dp:

            基于在树上的数据结构,通过DFS维护从根到叶子或从叶子到根的状态转移

    三.解题三部曲

        第一步:确定状态

        第二部:确定状态转移方程

        第三步:确定编程实现方式

        问题1:令 I 是一个 n 位十进制整数,如果将 I 划分为 k 段,可得到 k 个整数。这 k 个整数的乘积称为 I 的一个 k 

    乘积。对于给定的 n 、k 和 I,求出 I 的最大 k 乘积。

        (一):确定状态:dp[ i ][ j ]: 表示前 i 个数,分成 j 段

        (二):确定状态转移方程: dp[ i ][ j ] = max(dp[ i ][ j ], dp[ k ][ j - 1] * val[ k + 1][ i ]);

        (三):确定编程实现方式

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 20;
     4 char ch;
     5 int dp[maxn][maxn];
     6 int num[maxn],val[maxn][maxn];
     7 int main()
     8 {
     9     int n,k;       // n 位 k 段
    10     while(~scanf("%d%d",&n,&k))
    11     {
    12         memset(val,0,sizeof(val));
    13         for(int i=1;i<=n;i++)
    14         {
    15             cin>>ch;
    16             num[i] = ch - '0';
    17         }
    18 
    19         for(int i=1;i<=n;i++) val[i][i]=num[i];
    20 
    21         for(int i=1;i<=n;i++)
    22             for(int j=i+1;j<=n;j++)
    23                 val[i][j] = val[i][j-1]*10 + val[j][j];  //表示的是存放 i 到 j 所表示的整数。
    24 
    25         for(int i=1;i<=n;i++) dp[i][1] = val[1][i];     //只分成一段从第一位到i 位数字。
    26 
    27         for(int i=1;i<=n;i++)//位数
    28             for(int j=0;j<i;j++)//分割段数
    29                 for(int k=1;k<i;k++)
    30                     dp[i][j]=max(dp[i][j],dp[k][j-1]*val[k+1][i]);
    31 
    32         cout<<dp[n][k]<<endl;
    33     }
    34     return 0;
    35 }

        问题二: n 个整数(可能含有负数)组成的序列 a1,a2, ... , an,求该序列字段和的最大值,当所有整数都为负数时

    定义其最大子段和为0。

       

     1 #include <bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 ll a[100000];
     5 int main()
     6 {
     7     int n;
     8     ll sum = 0, temp = 0;
     9     cin>>n;
    10     for(int i = 1; i <= n; i++)
    11     {
    12         cin>>a[i];
    13         if(temp > 0) temp += a[i];
    14         else temp = a[i];
    15         sum = max(temp,sum);
    16     }
    17     cout<<sum<<endl;
    18     return 0;
    19 }

        问题三: 找出由 n 个 数字组成的序列的最长单调递增子序列。

        核心代码:

    ll CalcMaxL(ll b[],int n)  //计算序列最长递增子序列的长度
    {
        ll t = 0;
        for(int i = 0; i < n; i++)
            if(b[i] > t)
                t = b[i];
        return t;
    }
    ll DpLongestIncreasingSequence(ll a[], ll b[], int n)  //数组 b[]记录 0 ~ i 为结尾的最长递增子序列 
    {
        int i, j, k;
        for(i = 1, b[0] = 1; i < n; i++)
        {
            for(j = 0, k = 0; j < i; j++)
                if((a[j] <= a[i]) && (k < b[j]))
                    k = b[j];
            b[i] = k - 1;
        }
        return CalcMaxL(b,n);
    }
  • 相关阅读:
    大白痴学习webmagic
    selenium docs
    centos6.5单用户模式拯救系统
    使用Squid做代理服务器,Squid单网卡透明代理配置详解(转)
    Redundant Call to Object.ToString()
    Specify a culture in string conversion explicitly
    Benefits of Cold Showers: 7 Reasons Why Taking Cool Showers Is Good For Your Health
    Why Creating a Meaningful Morning Routine Will Make You More Successful
    git图示所有分支的历史
    Rewriting History with Git Rebase
  • 原文地址:https://www.cnblogs.com/Edviv/p/11783074.html
Copyright © 2020-2023  润新知