数位dp入门学习之路(正常枚举“过渡到”dfs枚举)

前言:数位dp就是换一种穷举方式。额......我第一次看这句话也懵,哎,资深学渣,来记个笔记先。

正常枚举“过渡到”dfs枚举(这里暂时是穷举的数为:1、10、100、1000、10000....,要穷举任意数在后面给出)

其实有些兄弟用了递推关系来做这类题,但个人感觉那种解题方式还是太花时间了。。。。。。。。。。

正常枚举:

#include <iostream>
#include <cstdio>
#define ll long long

using namespace std;

int main() {
    for (int i = 0; i <= 1000) {
        printf("%d
", i);
    }
    return 0;
} 

结果:略(看数学答案也是这样)

dfs枚举:注意pos参数的意思是枚举到当前数字的位数。dfs是从数字的高位往低位枚举(当数字的枚举是也是从小到大的)。num用于记录当前枚举的数字

dfs(pos=0, num); 表示只枚举长度为1的数字,最大数为9
dfs(pos=1, num); 表示只枚举长度为2的数字,最大数为99
dfs(pos=2, num); 表示只枚举长度为3的数字,最大数为999
最好自己动手测一下其他结果,不要光靠脑袋想,除非...........哈哈
#include <iostream>
#include <cstdio>
#include <vector>
#define ll long long

using namespace std;
// dfs穷举 
void dfs(int pos, vector<int> &num) {
    if (pos == -1) {
        // 打印数
        for (int i = 0; i < num.size(); i++)
            printf("%d", num[i]);
        printf("
"); 
        return;
    }
    for (int i = 0; i <= 9; i++) {
        num.push_back(i);// 添加 
        dfs(pos-1, num);
        num.erase(num.end()-1);// 回溯一下 
    }
}

int main() {
    vector<int> num;
    dfs(2, num);
    return 0;
} 

结果显示如下(不完整):

枚举到任意数:参数limit的引入(其他博主都是取的这个参数名)

正常枚举到任意数:(不用多说)

#include <iostream>
#include <cstdio>
#include <vector>
#define ll long long

using namespace std;

int main() {
    for (int i = 0; i <= 任意数; i++) {
        // ...... 
    }
    return 0;
} 

dfs任意数枚举:参数limit的用处,用来控制枚举上界位的数字,为Boolean值,为true的时候,表示当前枚举pos位上的数字有上界,相反则没有。

比如:任意数 = 321,limit初始为true

当枚举到百位上时,3就是百位上的上界,百位就只能取0、1、2、3,而当百位是3时,十位的枚举此时就有了上界2,同理,当百位为3,十位为2,则个位的上界为1。但是当枚举的百位小于3,也就是百位取值为0、1、2时,十位和个位的取值可以是0-9,此时不管怎么取值也不会超出最大值321,因为百位已经是0、1、2开头了,同样个位也是同样的道理。

#include <iostream>
#include <cstdio>
#include <vector>
#define ll long long

using namespace std;

int a[20];// 保存当前数字各个位上的数字 

// dfs穷举 
void dfs(int pos, bool limit, vector<int> &num) {
    if (pos == -1) {
        // 打印数
        for (int i = 0; i < num.size(); i++)
            printf("%d", num[i]);
        printf("
"); 
        return;
    }
    // 这里的up用来控制最大上界(就是枚举的数不能超过n = 123) 
    int up = limit?a[pos]:9;
    for (int i = 0; i <= up; i++) {
        num.push_back(i);// 添加 
        // limit && i == a[pos] 为true时表示如果当前位有上界,并且枚举到了最大上界值
        dfs(pos-1,  limit && i == a[pos], num);
        num.erase(num.end()-1);// 回溯一下,删除刚才添加的数字 
    }
}

int main() {
    vector<int> num; 
    int n = 123;
    int pos = 0;
    // 分解数字 
    while(n > 0) {
        a[pos++] = n%10;
        n /= 10;
    }
    dfs(pos-1, true, num);
    return 0;
} 

结果如下:

。。。。疫情过年好无聊

原文地址:https://www.cnblogs.com/hello-dummy/p/12298947.html