數位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——————題解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章