zoukankan      html  css  js  c++  java
  • POJ 1426 Find The Multiple --- BFS || DFS

    POJ 1426 Find The Multiple

    题意:给定一个整数n,求n的一个倍数,要求这个倍数只含0和1

    参考博客:点我 

    解法一:普通的BFS(用G++能过但C++会超时)

        从小到大搜索直至找到满足条件的数,注意最高位一定为1

        假设 n=6  k即为当前所求的目标数,不满足条件则进一步递推 (i 为层数(深度),在解法二的优化中体现,此时可以不管) 


        1%6=1 (k=1)  i=1
        {
          (1*10+0)%6=4 (k=10)  i=2
          {
            (10*10+0)%6=4 (k=100)  i=4
            {
              (100*10+0)%6=4 (k=1000)  i=8
              (100*10+1)%6=5 (k=1001)  i=9
            }
            (10*10+1)%6=5 (k=101)  i=5
            {
              (101*10+0)%6=2 (k=1010)  i=10
              (101*10+1)%6=3 (k=1011)  i=11
            }
          }

          (1*10+1)%6=5 (k=11)  i=3
          {
            (11*10+0)%6=2 (k=110)  i=6
            {
              (110*10+0)%6=2 (k=1100)  i=12
              (110*10+1)%6=3 (k=1101)  i=13
            }
            (11*10+1)%6=3 (k=111)  i=7
            {
              (111*10+0)%6=0 (k=1110)  i=14 有解
              (111*10+1)%6=1 (k=1111) 由于前面有解,这个余数不存储
            }
          }
    }

    可以看到,如此反复枚举下去,直至找到目的数k为止,注意若当前k不满足条件,则将k*10 和k*10 + 1入队以便进一步判断

    以下是解法一的代码,用G++能过,但用C++超时(我是在hust交的),不知道为什么!

    /* POJ 1426 Find The Multiple BFS 用C++超时但G++过了*/
    #include <cstdio>
    #include <queue>
    using namespace std;
    
    /*返回最大能整除n的只有1和0组成的数*/
    long long bfs(int n){
        long long tmp;
        queue<long long> q;
        q.push(1);
        while (!q.empty()){
            tmp = q.front();
            q.pop();
            if (tmp % n == 0){
                return tmp;
            }
            q.push(tmp * 10);
            q.push(tmp * 10 + 1);
        }
        return 0;
    }
    
    int main()
    {
        int n;
        while (scanf("%d", &n) == 1 && n){
            printf("%lld
    ", bfs[n]);
        }
    
        return 0;
    }
    View Code

    解法二:优化的BFS(C++能过)

    由于C++超时,于是我参考了以下别人的代码,地址上面已给出,但为了加深记忆,还是自己写一遍!

    同余定理的应用:

            (a+b)%n = (a%n + b%n)%n

            (a*b)%n =  (a%n * b%n)%n

    在解法一中,由于一直*10, k有可能出现越界,具体请参考原博客,在这里只写余数优化过程:

    取解法一中的任意式子:

      前一层: mod =  (11*10 + 0)%6 = 2, k = 110, i = 6, k % 6 = 2

      后一层: mod = (k'*10 + 0) %6   //注意这里的k'为上一层的k,即110, 另此层k为110*10 + 0, i 为6 * 2

               =( (k'*10)%6 + 0%6 ) % 6

             =( (k'%6 * 10%6) % 6 + 0%6) % 6   //k'%6即为上一层的mod,记为mod', 在这个例子中就是2, 另k'%6 = mod' = mod'%6

               =( (mod'6 * 10%6) % 6 + 0%6) % 6

             =( (mod' * 10) % 6 + 0 % 6) % 6

             = (mod'*10 + 0) % 6;  //即当前层的mod=前一层的mod*10 + 0 (具体是0还是1和i有关) 因为0、1是循环取的

    为了加强理解,再推导一遍i为奇数的过程

      前一层:mod =  (11*10 + 0)%6 = 2, k = 110, i = 6, k % 6 = 2

      后一层:  mod = (k'*10 + 1)  % 6   //此层 k = 110*10+1, i 为6*2+1

              = ( (k'%6 * 10%6) % 6 + 1 % 6) % 6

              = ( mod' * 10 + 1) % 6  //即当前层的mod=前一层的mod*10 + 1(具体是0和1和i有关)

    这样就化简了求模的过程,共经过i步求模获得当前的目标数k % n = 0(但此时并不知道k具体的值),只知道求mod的过程

    要通过操作数获取k,我是这样理解的:

      经过i步得到满足条件的数k(尽管k暂时还不知道), 由于每个数会产生两个分支,即k是由 i / 2 层的数k'递推而来的。 即 k'/2 * 2 + 0或1. 因此要知道k的末位是0还是1只要考虑当前k的奇偶性,因为2 * i / 2一定是偶数,奇偶性就是由后面的1或者0来决定的!如果是奇数,则证明当前k的最后一位是1,否则是0,值得注意的是:k的奇偶性和i的奇偶性恰巧是相同的,由于每个数会产生两个新的数字,可以看成是一棵二叉树, 如图:

    结点编号即为获取当前k(括号里的数)所需要的操作步数,可以看到k与编号的奇偶性是恰好相同的,因此利用操作步数i, 循环i%2 与i/ = 2 就可以获取目标数的各个位(注意是从叶子到根得到的各个位置上的数(即先得到后面的位的数),因此输出时需要到过来),

    优化后的BFS的代码:

    /* POJ 1426 Find The Multiple BFS 优化*/
    #include <cstdio>
    
    int mod[524285]; //寸模,参考别人的计算这是最小的AC下限
    
    int main()
    {
        int n;
        while (scanf("%d", &n) == 1 && n){
            mod[1] = 1;
            int i;
            for (i = 2; mod[i - 1] != 0; ++i){
                //该公式前面已证明, 注意:i为奇偶数分别对应 i%2 = 1和0
                mod[i] = (mod[i/2] * 10 + i % 2) % n;  // i/2为前一层
            }
            --i; //i此时为取模的次数
            int p = 0;
            while (i){
                mod[p++] = i % 2; //操作次数转化成所要的数--->k(可用二叉树理解)
                i /= 2;
            }
            while (p){
                printf("%d", mod[--p]); //逆序输出即为目的数
            }
            printf("
    ");
        }
    
        return 0;
    }
    View Code

    解法三: 这题还可以用DFS通过控制递归深度直接过

    /* POJ 1426 Find The Multiple --- DFS */
    #include <cstdio>
    
    int n;
    bool flag;
    
    void dfs(unsigned long long tmp, int i){
        if (flag || i > 19)
            return;
        if (tmp % n == 0){
            flag = 1;
            printf("%llu
    ", tmp);
            return ;
        }
        else{
            dfs(tmp * 10, i+1);
            dfs(tmp * 10 + 1, i+1);
        }
    }
    
    int main()
    {
        while (scanf("%d", &n) == 1 && n){
            flag = 0;
            dfs(1,0);
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    SQL中distinct的用法
    python requests 高级用法 -- 包括SSL 证书错误的解决方案
    odoo js
    线程池的理解及使用
    单点登录原理及简单实现
    如何重写hashCode()和equals()方法
    多线程中的Lock小结
    Sql语句的优化摘要
    Spring事务管理
    并发编程之原子性、可见性、有序性的简单理解
  • 原文地址:https://www.cnblogs.com/tommychok/p/5022214.html
Copyright © 2011-2022 走看看