HDU 2089


http://acm.hdu.edu.cn/showproblem.php?pid=2089

基礎的數位dp,當初不懂數位dp水過去的,今天重新寫一下,解釋看注釋

預處理+遞推

學自http://wenku.baidu.com/view/9de41d51168884868662d623.html

#include <iostream>
using namespace std  ;
int f[8][10] ;//f[i][j]表示第i位是數j時符合條件的數字數量 
int digit[9] ;//digit[i]表示n從右到左第i位是多少 
void Init()
{
    f[0][0]=1 ;
    for(int i=1 ;i<=7 ;i++)
    {
        for(int j=0 ;j<10 ;j++)//枚舉第i位 
        {
            for(int k=0 ;k<10 ;k++)//枚舉第i-1位
            {
                if(!(j==6 && k==2) && j!=4)//如果符合條件
                    f[i][j]+=f[i-1][k] ; 
            } 
        }
    }
}
int callen(int n)//計算n的長度 
{
    int cnt=0 ;
    while(n)
    {
        cnt++ ;
        n/=10 ;
    }
    return cnt ;
} 
void caldigit(int n,int len)//計算n的digit數組 
{
    memset(digit,0,sizeof(digit)) ;
    for(int i=1 ;i<=len ;i++)
    {
        digit[i]=n%10 ;
        n/=10 ;
    }
}
int solve(int n)//計算[0,n]區間滿足條件的數字個數 
{
    int ans=0 ;
    int len=callen(n) ;
    caldigit(n,len) ;
    for(int i=len ;i>=1 ;i--)
    {
        for(int j=0 ;j<digit[i] ;j++)//枚舉第i位取值 
        {
            if(!(j==2 && digit[i+1]==6) && j!=4)//第i位滿足條件 
                ans+=f[i][j] ;
        }
        if(digit[i]==4 || (digit[i]==2 && digit[i+1]==6))//第i位已經不滿足條件,則i位以后都不可能滿足條件,結束循環 
            break ;
    }
    return ans ; 
}
int main()
{
    Init() ;
    int n,m ;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0 && m==0)
            break ;
        printf("%d\n",solve(m+1)-solve(n)) ;//用[0,m]-[0,n)即可得到區間[n,m] 
    }
    return 0 ;
}
View Code

記憶化搜索

學自http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html
dfs里的e額外做下解釋,當前位隨意填的概念這么理解,比如一個數250,第一位填1,第二位填0-9都沒問題,但是如果第一位填的是2,那么第二位只能填0-5

#include <iostream>
using namespace std ;
int f[8][2] ;//dp[i][0]:前i位符合要求 dp[i][1]:前i位符合要求且i+1位是6
int digit[9] ;//digit[i]表示n從右到左第i位是多少 
int dfs(int i,int s,bool e)//i表示當前位,s表示i位之前的狀態,e表示當前位是否可以隨意填寫 
{ 
    if(i==0)
        return 1 ;
    if(!e && f[i][s]!=-1)
        return f[i][s] ;
    int res=0 ;
    int u=e?digit[i]:9 ;
    for(int d=0 ;d<=u ;d++)
    {
        if(d==4 || (s && d==2))
            continue ;
        res+=dfs(i-1,d==6,e&&d==u) ;
    }
    return e?res:f[i][s]=res ;
}
int callen(int n)//計算n的長度 
{
    int cnt=0 ;
    while(n)
    {
        cnt++ ;
        n/=10 ;
    }
    return cnt ;
}
void caldigit(int n,int len)//計算n的digit數組 
{
    memset(digit,0,sizeof(digit)) ;
    for(int i=1 ;i<=len ;i++)
    {
        digit[i]=n%10 ;
        n/=10 ;
    }
}
int solve(int n)//計算[0,n]區間滿足條件的數字個數 
{
    int len=callen(n) ;
    caldigit(n,len) ;
    dfs(len,0,1) ;
}
int main()
{
    int n,m ;
    memset(f,-1,sizeof(f)) ;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0 && m==0)
            break ;
        printf("%d\n",solve(m)-solve(n-1)) ;//用[0,m]-[0,n)即可得到區間[n,m]
    }
    return 0 ;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM