HDU 4734 数位DP

http://www.cnblogs.com/Griselda/archive/2013/11/20/3433295.html

 

上面那个链接讲得挺清楚,简单贴一下:

数位DP,用来学习数位DP了。

  <数位DP>

    所谓数位DP就是基于考虑数字的每一位来转移的DP。

    例如求比456小的数,可以这么考虑,

        4          5               6

          4        5             (0~6)

        4       (0~4)         (0~9)

        (0~3)(0~9)         (0~9)

    然后我们就可以考虑用dp[len][pre]表示长度为len,以pre开头的符合条件的数的个数。

    这样就可以得到转移方程了。

 

  而对于这道题,我们可以用dp[len][pre]表示长度为len且权值不大于pre的数。

  这道题用记忆化搜索,除边界条件外记录dp[len][pre]的值,下一次发现以前已经计算过了就可以直接return;

 

  初值:dp[len][pre] = 0; 

     dfs(len, pre, flag)表示求长度为len,不超过pre的所有符合条件的值。其中flag是用来控制边界的。

     dfs过程中当深搜的边界,发现len < 0,pre >=0 的时候就返回1.

 

这里主要想讲一下为什么想到用数位DP,或者说数位DP可以解决什么问题

题目是给出一个限定值,求这个限定值下满足条件的个数。而这个值求得的过程是每个位分别运算得出来的,所以我们很自然可以每个位分别去算,一直算到最后一个位得出结果。

dp[len][pre]表示长度为len且权值不大于pre的数

 

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <queue>
#include <cctype>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <sstream>
using namespace std;

#define mem(a,b) memset(a,b,sizeof(a))
#define pf printf
#define sf scanf
#define spf sprintf
#define pb push_back
#define debug printf("!\n")
#define MAXN 1000000000 +5
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#define LL long long
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define pqueue priority_queue
#define INF 0x3f3f3f3f

#define ls (rt<<1)
#define rs (rt<<1|1)

int n,m;

int a[20];

int dp[20][200000];

int dfs(int pos,int pre,bool flag)
{
    if(pre<0) return 0;
    if(pos<0) return pre>=0;
    if(!flag && dp[pos][pre] != -1) return dp[pos][pre];
    int e = flag?a[pos]:9;
    int ans  = 0;
    for(int i = 0;i<=e;i++)
    {
        ans += dfs(pos-1,pre-i*(1<<pos),flag && i==e);
    }
    if(!flag) dp[pos][pre] = ans;
    return ans;
}

int main()
{
    int t,kase=1,i,j,k;
    sf("%d",&t);
    mem(dp,-1);
    while(t--)
    {
        sf("%d%d",&n,&m);
        int len = 0,pre = 0,tmp=1;
        while(m)
        {
            a[len++] = m%10;
            m/=10;
        }
        while(n)
        {
            pre+= tmp * (n%10);
            tmp*=2;
            n/=10;
        }
        /*
        for(i=0;i<len;i++) pf("%d\n",a[i]);
        pf("%d %d\n",len,pre);
        */
        pf("Case #%d: %d\n",kase++,dfs(len-1,pre,true));
    }
    return 0;

}

 

posted @ 2016-08-06 01:11  qlky  阅读(156)  评论(0编辑  收藏  举报