數位dp小結

來源:互聯網
上載者:User
數位dp如何入門

我最初在網上漫遊了一天,終於找到了一個適合自己的學習方式,這裡分享給大家。搜數位dp大部分都是記憶化搜尋寫的,因為這個搜尋是反向的,所以一看是看上去真的什麼都看不懂,因此我們首先學一下遞推版的,這裡給出網址,大家可以去看一下寫的真的很好,認真看就能看明白初探數位dp,然後看懂了之後就手寫代碼,通常寫hdu2089(不要62)這個入門題,這樣我們就可以開始看記憶化搜尋了,只是反向而已,那麼既然有正推為什麼還要學記憶化,首先學會之後比較好學,然後就是記憶化其實真的不難,學會之後很好處理。

給出記憶化的模板:
摘自Beginner

//    pos    = 當前處理的位置(一般從高位到低位)//    pre    = 上一個位的數字(更高的那一位)//    status = 要達到的狀態,如果為1則可以認為找到了答案,到時候用來返回,//            給計數器+1。//    limit  = 是否受限,也即當前處理這位能否隨便取值。如567,當前處理6這位,//            如果前面取的是4,則當前這位可以取0-9。如果前面取的5,那麼當前//            這位就不能隨便取,不然會超出這個數的範圍,所以如果前面取5的//            話此時的limit=1,也就是說當前只可以取0-6。////    用DP數組儲存這三個狀態是因為往後轉移的時候會遇到很多重複的情況。int    dfs(int pos,int pre,int status,int limit){    //已結搜到盡頭,返回"是否找到了答案"這個狀態。    if(pos < 1)        return    status;    //DP裡儲存的是完整的,也即不受限的答案,所以如果滿足的話,可以直接返回。    if(!limit && DP[pos][pre][status] != -1)        return    DP[pos][pre][status];    int    end = limit ? DIG[pos] : 9;    int    ret = 0;    //往下搜的狀態表示的很巧妙,status用||是因為如果前面找到了答案那麼後面    //還有沒有答案都無所謂了。而limti用&&是因為只有前面受限、當前受限才能    //推出下一步也受限,比如567,如果是46X的情況,雖然6已經到盡頭,但是後面的    //個位仍然可以隨便取,因為百位沒受限,所以如果個位要受限,那麼前面必須是56。    //    //這裡用"不要49"一題來做例子。    for(int i = 0;i <= end;i ++)        ret += dfs(pos - 1,i,status || (pre == 4 && i == 9),limit && (i == end));    //DP裡儲存完整的、取到盡頭的資料    if(!limit)        DP[pos][pre][status] = ret;    return    ret;}

這裡是我自己寫的幾道練手題: hdu 2089 不要62

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int maxn = 35;LL dp[maxn][10][2],bit[maxn];LL dfs(int pos,int pre,int is,int f){    if(pos < 1) return is;    if(!f && dp[pos][pre][is] != -1) return dp[pos][pre][is];        int last = f?bit[pos]:9;    LL res = 0;    for(int i = 0; i <= last; i++){        res += dfs(pos-1, i, is||(pre == 4 && i == 9), f&&i==last);    }    if(!f) dp[pos][pre][is] = res;    return res;}LL solve(LL n){    int len = 0;    while(n){        bit[++len] = n%10;        n /= 10;    }    return dfs(len, 0, 0, 1);  //當前的位置,前一個數是多少,該書中是否已經含有49,f我不知道什麼意思}int main(){    int T;    scanf("%d", &T);    while(T--){        LL n;        scanf("I64d", &n);        printf("%I64d\n", solve(n));    }    return ;}
hdu 3555 bomb
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int maxn = 35;LL dp[maxn][10][2],digit[maxn];LL dfs(int pos,int pre,int is,int limit){  //limit表示是否有限制    if(pos < 1) return is;  //是否有49    if(!limit && dp[pos][pre][is] != -1) return dp[pos][pre][is];    int last = limit ? digit[pos]:9;  //f用來判斷是否能隨意取    LL ret = 0;    for(int i = 0; i <= last; i++)        ret += dfs(pos-1, i, is||(pre==4 && i==9), limit&&i==last);    if(!limit) dp[pos][pre][is] = ret;    return ret;}LL solve(LL n){    int len = 0;    memset(digit, 0, sizeof(digit));    while(n){        digit[++len] = n%10;        n /= 10;    }    return dfs(len, 0, 0, 1);}int main(){    int T;    scanf("%d", &T);    memset(dp, -1, sizeof(dp));    while(T--){        LL n;        scanf("%I64d", &n);        printf("%I64d\n", solve(n));    }    return 0;}
hdu 4722 Good Numbers
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int MOD = 10;const int maxn = 25;LL dp[maxn][15],dig[maxn];LL dfs(int pos, int mod, int limit){    if(pos < 1) return mod == 0;    if(!limit && dp[pos][mod] != -1) return dp[pos][mod];    int len = limit?dig[pos]:9;    LL ret = 0;    for(int i = 0; i <= len; i++)        ret += dfs(pos-1, (mod+i)%MOD, limit&&i==len);    if(!limit) dp[pos][mod] = ret;    return ret;}LL solve(LL n){    LL len = 0;    while(n){        dig[++len] = n%10;        n /= 10;    }    return dfs(len, 0, 1);}int main(){    int T;    scanf("%d", &T);    LL A,B;    memset(dp, -1, sizeof(dp));    for(int kase = 1; kase <= T; kase++){        scanf("%I64d%I64d", &A, &B);        printf("Case #%d: ", kase);        if(A == 0) printf("%I64d\n", solve(B));  //注意A取0,那麼A-1小於0,不合理,因此需要特判        else printf("%I64d\n", solve(B) - solve(A-1));    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.