Tmotfl的博客

博客地址 tmotfl.top 欢迎访问

数位Dp 学习笔记

前面

最近学了点数位DP,也码了几个题,写点学习笔记

数位DP

数位DP就是在数位上进行DP,(个位,十位,百位之类的)
一般数位DP,都会让求在某一区间内满足某一种限定的数的数量。
DP的方式一般是DFS+记忆化。
状态的话就是dp[pos][..],pos表示第pos位状态为..的满足题目限制的数量
对了…
一般我们在进行dfs之前要对枚举上界进行分解,就是把各个位分离,这样既容易记录状态,也容易判断枚举的范围。
看一下代码应该就理解的差不多了.

int solve(int x)
{
    pos=0;//一定要记住啊每一次都要变成0,写题的时候老是忘
    while(x)
    {
        a[pos++]=x%10;//把各个位分离开
        x/=10;
    }
    return dfs(pos-1,....,true);
}

下面说一下dfs的时候对于上界的控制:
我们在solve里对枚举上界进行了拆分,
然后我们在dfs的时候设置一个bool变量limit来记录上一次dfs是否到达的上一个位的上界,
如果到达了上一个位的上界,那我们在这一次dfs的时候最大就只能枚举到这一位的上界
如果没有到达上一个位的上界,那么我们就可以一直枚举到9;
举个例子:
假设我们枚举的上界是678,假如我们枚举第一位也就是百位是6的话,那我们第二位也就是十位就只能枚举到7是不是,如果大于7的话就会超过枚举上界;相反,假如我们在枚举第一位的时候百位小于6,那么我们第二位就可以在09之间任意枚举了。因为5XX显然小于678.
对于上界的控制还需要注意的就是在开始dfs,要把limit设置成为true,这样才能保证枚举一直不超过上界。
然后是对于前导0的处理:
和上界控制差不多,对于前导0我们也是用一个bool变量lead来进行控制。
假若上一位是存在前导0且当前位又恰好选择了0,那么leadtrue;反之为0

然后就是对于dfs的讲解了:

    //分别是枚举的位数,状态,是否到达枚举上界,是否有前导0
    int dfs(int pos,int S,int limit,int lead)
    {
        if(pos==-1) //因为上面是从pos=0开始拆分的所以这个是搜索的结束
            return 1;//对于返回:一般的题目中都是要对最后的状态进行判断,合法的话返回1,不合法的话返回0,做题多了也就了解套路了
        if(dp[pos][S]==-1 && !limit && !lead) //对于没有特殊情况的话,直接上记忆化搜索
            return dp[pos][S];
        int up=limit ? a[pos] : 9;//这里是上界判断
        int ans=0;//记录答案
        for(int i=0;i<=up;i++)//开始枚举当前位所选的数字
        {
            ........//一般会有一些判断
            ans+=dfs(pos-1,S...,limit && i==up,lead && i==0);
            //假若上一位到达了枚举上界且这一位也是枚举上界的话,那么下一位也必须是枚举上界,两个条件缺一不可。
            //lead是用来判断前导0
        }
        if(!limit && !lead) //除去特殊情况,进行记忆化
            dp[pos][S]=ans;
        return ans; //返回
    }

题目

学完数位DP之后也码了几道题,在我的博客里都有题解.(按照我做的顺序给出)
1.不要62 —————— 题解
2.HDU4734——————题解
3.POJ3252——————题解
4.HDU3709——————题解

阅读更多
个人分类: 数位Dp 学习笔记
上一篇【UVA10944】Nuts for nuts.. 状压DP
下一篇【HDU2089】不要62 数位Dp
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭