zoukankan      html  css  js  c++  java
  • 【BFS+同余模定理】Find The Multiple(POJ1426)

    Description

    Given a positive integer n, write a program to find out a nonzero multiple m of n whose decimal representation contains only the digits 0 and 1. You may assume that n is not greater than 200 and there is a corresponding m containing no more than 100 decimal digits.

    Input

    The input file may contain multiple test cases. Each line contains a value of n (1 <= n <= 200). A line containing a zero terminates the input.

    Output

    For each value of n in the input print a line containing the corresponding value of m. The decimal representation of m must not contain more than 100 digits. If there are multiple solutions for a given value of n, any one of them is acceptable.

    Sample Input

    2
    6
    19
    0

    Sample Output

    10
    100100100100100100
    111111111111111111

    Source

     
    题目大意
    给出一个整数n,(1 <= n <= 200)。求出任意一个它的倍数m,要求m必须只由十进制的'0'或'1'组成,m的位数不超过100个。
     
    分析
    (摘自http://blog.csdn.net/lyy289065406/article/details/6647917)
     
    设6的 ”01十进制倍数” 为k,那么必有k%6 =0。
    用BFS求k值
     
    1、先搜索k的最高位,最高位必为1,则此时k=1,但1%6 =1  !=  0

    因此k=1不是所求,存储余数 1

    2、搜索下一位,下一位可能为0,即 k*10+0,此时k=10,那么k%6=4

                可能为1,即 k*10+1,此时k=11,那么k%6=5

    由于余数均不为0,即k=10与k=11均不是所求

    3、继续搜索第三位,此时有四种可能了:

    对于k=10,下一位可能为0,即 k*10+0,此时k=100,那么k%6=4

                  下一位可能为1,即 k*10+1,此时k=101,那么k%6=5

    对于k=11,下一位可能为0,即 k*10+0,此时k=110,那么k%6=2

                  下一位可能为1,即 k*10+1,此时k=111,那么k%6=3

    由于余数均不为0,即k=100,k=101,k=110,k=111均不是所求

    4、继续搜索第四位,此时有八种可能了:

    对于k=100,下一位可能为0,即 k*10+0,此时k=1000,那么k%6=4

                  下一位可能为1,即 k*10+1,此时k=1001,那么k%6=5

    对于k=101,下一位可能为0,即 k*10+0,此时k=1010,那么k%6=2

                  下一位可能为1,即 k*10+1,此时k=1011,那么k%6=3

    对于k=110,下一位可能为0,即 k*10+0,此时k=1100,那么k%6=2

                  下一位可能为1,即 k*10+1,此时k=1101,那么k%6=3

    对于k=111,下一位可能为0,即 k*10+0,此时k=1110,那么k%6=0

                  下一位可能为1,即 k*10+1,此时k=1111,那么k%6=1

    我们发现k=1110时,k%6=0,即1110就是所求的倍数

    从上面的演绎发现,用BFS是搜索 当前位数字 (除最高位固定为1),因为每一位都只有0或1两种选择,当k%n==0,即找到了所求倍数。但是因为所求的余数可能会非常大所以下面试着从余数和所求倍数的关系表示大数。

    我们先将上面的bfs汉字描述写成如下的数字形式,便于发现规律

    1%6=1  (k=1)

     (1*10+0)%6=4  (k=10)

    {

        (10*10+0)%6=4   (k=100)

        {

            (100*10+0)%6=4  (k=1000)

            (100*10+1)%6=5  (k=1001)

        }

        (10*10+1)%6=5  (k=101)

        {

            (101*10+0)%6=2  (k=1010)

            (101*10+1)%6=3  (k=1011)

        }

    }

       (1*10+1)%6=5  (k=11)

    {

        (11*10+0)%6=2   (k=110)

        {

            (110*10+0)%6=2  (k=1100)

            (110*10+1)%6=3  (k=1101)        

        }

        (11*10+1)%6=3   (k=111)

        {

            (111*10+0)%6=0  (k=1110)   有解

            (111*10+1)%6=1  (k=1111)  由于前面有解,这个余数不存储

        }

    }

    }

    ①大数问题:
    首先说一下,下面要用到的同余模定理的公式

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

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

    我们用同余模定理对上述的大数进行优化,如(原文博主的例子写错了一个数,应该把+1改成+0)
     
    如前一步(11*10+0)%6=2,即k=110,k%6=2
    当前步(110*10+0)%6=2
    由同余模定理(110*10+0)%6=((110*10)%6+0)%6
                =((110%6*10%6)%6)%6
                =((2*10%6+0%6)%6)%6
                =(2*10+0)%6
    发现此时的k=110变成了k=2,所以可以用 前一步操作得到的余数 代替 当前步的k值。
    因为n<=200所以n的余数不会很大,这样就解决了大数问题。
     
    ②求余操作的次数与倍数的关系
    再观察上面的数字描述发现,n=6时,求余操作进行了14次,对应地,BFS时*10的操作也进行了14次。
    令i=14,i%2恰好就是 6 的01十进制倍数的最低位数字
    i/2 再令 i%2 ,恰好就是 6 的01十进制倍数的 次低位数字,循环这个操作,直到i=0,就能得到 6的 01倍数(一个01队列),倒序输出就是所求
     
    参考代码
    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    int mod[524286];//这个数组大小,我不明白是怎么来的,还请路过的大佬解释下。
    int main()
    {
    
        int n;
        int i;
        while(1){
            scanf("%d",&n);
            if(!n)
            break;
            mod[1]=1%n;
            ///这里的前一步不是-1的上一步,是/2后的前一步。。
            for(i=2;mod[i-1]!=0;i++){//利用同余模定理,从前一步的余数mod[i/2]得到下一步的余数mod[i]
                mod[i]=(mod[i/2]*10+i%2)%n;
                //mod[i/2]*10+i%2模拟了BFS的双入口搜索
                //当i为偶数时,+0,即取当前位数字为0  。为奇数时,则+1,即取当前位数字为1
            }
    
            i--;
            int pm=0;
            while(i)
            {
                mod[pm++]=i%2;   //把*10操作转化为%2操作,逆向求倍数的每一位数字
                i/=2;
            }
            while(pm)
            printf("%d",mod[--pm]);
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    237. Delete Node in a Linked List
    430. Flatten a Multilevel Doubly Linked List
    707. Design Linked List
    83. Remove Duplicates from Sorted List
    160. Intersection of Two Linked Lists
    426. Convert Binary Search Tree to Sorted Doubly Linked List
    142. Linked List Cycle II
    类之间的关系
    初始化块
    明确类和对象
  • 原文地址:https://www.cnblogs.com/LuRenJiang/p/7491328.html
Copyright © 2011-2022 走看看