zoukankan      html  css  js  c++  java
  • 区间DP,数位DP

    dp(动态规划)顾名思义便是动态的一种规划,而这种规划往往会跟状态,状态转移方程,记忆化搜索扯上关系,当然DP也是各个OI考试的必考点和常考点,在毒瘤出题人的折磨下,出现了许许多多的动态规划,有线性,背包,环形,插头,区间,数位,状压等等各种动态规划,最近刚刚吧区间和数位DP学会。

    区间DP:一看就知道肯定与区间有关,这类DP主要处理一些区间的最值和各种状态,貌似ST表就相当于区间DP,说到区间DP,就不得不提一个题——石子合并。

    题目

    我们乍一看似乎可以贪心,但是这个题跟合并果子可是万万不同,合并果子是一道堆,而这道题还是环形,因此我们看题一定要看清楚,不然就会GG。我们要先化环为链。

    我们难道做DP就要先想这是什么DP吗,错了,我们一定要先想状态和状态转移方程,慢慢慢慢就会知道这是什么DP了。再看这道题,我们先处理前缀和,这样好控制一段区间里的所有石子的值,到合并时,肯定要加上这段区间里的所有值,因此我们要处理前缀和,方便合并。

    这样的话我们可以轻易的写出状态转移方程:

        dp1[i][j]=min(dp1[i][j],dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]);//最小值
        dp2[i][j]=max(dp2[i][j],dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]);//最大值

    看这个状态转移方程,如果你写出了状态转移方程也不要大意,我们看i表示左端点,而j表示右端点,k表示中间断点。而显而易见,k一定>i,<j.

    又因为原状态转移方程中出现了k+1,所以我们应该在枚举的时候,让i从2*n-1到1。

    这样这个题就很好写了。

    代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;    
    int n,minn=0x7ffffff,maxn;
    int data[10000],dp1[1000][2000],dp2[1000][2010],sum[10000];//sum表示前缀和,dp1,dp2,分别表示最大最小值。
    int main()
    {
    
        cin>>n;
        for(int i=1;i<=n;i++)
        {
        cin>>data[i];
        data[i+n]=data[i];//环形 
        }
        for(int i=1;i<=n*2;i++)
        sum[i]=sum[i-1]+data[i];
        for(int i=n*2-1;i>0;i--)//因为是环形,所以要从n*2-1开始
        {
            for(int j=i+1;j<i+n;j++)
            {
                dp1[i][j]=0x3f3f3f;
                for(int k=i;k<j;k++)
                {
                    dp1[i][j]=min(dp1[i][j],dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]);
                    dp2[i][j]=max(dp2[i][j],dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]);
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
        minn=min(minn,dp1[i][i+n-1]);
        maxn=max(maxn,dp2[i][i+n-1]); 
        }
        printf("%d
    %d
    ",minn,maxn);
        return 0;
    }    

    这个题也是一道很经典的题了,从此我们可以得出区间DP的一个普遍规律(仅供参考,每个DP都不一样,所以不要照着葫芦画葫芦)。

    我们要先枚举左端点,然后枚举区间长度或右端点,然后枚举中间断点用于状态转移方程。

    数位DP:

    不得不说数位DP还是挺难的,到底有多难呢,NOIP不考(为了长远打算)

     https://wenku.baidu.com/view/9de41d51168884868662d623.html 

    数位DP的题目特点是让你求一段区间内的满足一个特点的数的个数,我们首先看这些数有什么特点,然后枚举看这个数的第一位是否<=他给出的条件,如果满足就可以,如果第一位恰好在边界上,那我们就不能随便枚举了,这时候我们就应该再判断下一位,这样依次判断直到满足或不满足。

  • 相关阅读:
    mysql安装
    Python中的 _init__和 _new__的区别
    MySQL系列
    彻底解决编码问题
    人生三问之前后端分离是什么鬼?
    什么是内存泄漏?什么是内存溢出?
    目录
    虚拟环境的使用
    如何为Redis中list中的项设置过期时间
    Redis分布式锁的python实现
  • 原文地址:https://www.cnblogs.com/liuwenyao/p/9319466.html
Copyright © 2011-2022 走看看