[ 题解 ] [ BFS ] POJ 1426 - Find The Multiple
VJudge题目:https://cn.vjudge.net/contest/279018#problem/L
即POJ 1426 - Find The Multiple:http://poj.org/problem?id=1426
题目要求:
给出一个不大于200的整数n,要求找到任意一个n的倍数(十进制),并且这个倍数只由1与0组成,最多100位。
输入输出:输入以0结束。
示例:
Input:
2 6 19 0
Output:
10 100100100100100100 111111111111111111
非常容易想出从1开始搜索,然后是10与11,进而为100、101、110、111,等等。
如果你知道二叉树,这图你一定见过,这里我画了一个二进制版本。把这些数字看成十进制,所有1与0组成的数都在这树中。
这棵树是无限高的,虽然题目限制了100层,但是也不能用DFS去做。
比如输入一个3,这里最小的倍数是111,但是假如你写的BFS优先查找左节点,一直搜索到1e100(100层)也没有遇到3的倍数,就会浪费很多时间。因此此处要一层一层地搜索。
虽然我这里搬出了二叉树的图,但是此处并不需要建树。你需要的仅仅只是一个队列。想象一下搜索过程:
一开始是1,它有两个子节点1*10、1*10+1,入队。队列里只有10和11;
然后就是10,子节点10*10、10*10+1,入队。队列有11、100、101;
11,子节点11*10、11*10+1,入队。队列有100、101、110、111……
在父层未搜索完之前,各个子节点是处于等待的状态的。这就保证了父层优先被遍历,也就是所谓的宽度优先搜索(BFS)。
知道怎么做后代码应该很容易写出来。至于队列怎么写,此处只能用C++ STL提高的queue。
100位数字怎么存?这个先不要管,直接用long long,因为最大也就19位数。
代码如下:
1 #include <cstdio> 2 #include <string> 3 #include <stdlib.h> 4 #include <queue> 5 using namespace std; 6 queue <long long> que; 7 int cleanQueue() 8 { 9 while(que.size()) 10 { 11 que.pop(); 12 } 13 } 14 15 int main() 16 {Start:; 17 int N; 18 scanf("%d",&N); 19 if(N==0)return 0; 20 cleanQueue(); 21 que.push(1); 22 long long tmp; 23 while(1) 24 { 25 tmp=que.front(); que.pop(); 26 if( tmp%N==0) 27 { 28 printf("%lld\n",tmp); 29 break; 30 } 31 else 32 { 33 tmp=tmp*10; 34 que.push(tmp);que.push(tmp+1); 35 } 36 } 37 goto Start; 38 }
我不怎么会用C++,本来自己写的C队列没啥毛病OJ说超内存(本题限10000KB)。我不知道是不是因为calloc申请来的地址太大的缘故。
这沙雕C++编译器还逼我在calloc前写指针转换,C编译器反而不会,神奇。
至于为什么可以直接用long long,因为有种操作叫打表。先把200个数各自的倍数找出来,提交给OJ的程序直接把答案报出来就完了。
打表就是先写一个程序,把从1到200每个数的倍数找到,输出为文本;
另一个程序把这200个倍数放入long long answer[202]数组,按下标输出答案。
在此之前你并不知道数字有多大,先按题目要求搞一个100位大数。然后在本地类似地BFS就行了。
大数写得太丑运算量挺大的,随便超时。不然怎么要本地打表?
代码如下:
1 #include <stdio.h> 2 #include <string.h> 3 short bin[102]={0}; 4 5 int main() 6 { 7 int p1(); int div(int base); int printanswer(); 8 for(int base=1;base<=200;base++) 9 { 10 memset(bin,0,102*sizeof(short)); 11 while(1) 12 { 13 p1(); 14 if(div(base)==0) 15 { 16 // printf("%d,",base); 17 printanswer(); 18 break; 19 } 20 } 21 } 22 return 0; 23 } 24 25 int p1() 26 { 27 int bit=101; 28 bin[101]+=1; 29 while(1) 30 { 31 if(bin[bit]==2) 32 { 33 bin[bit]=0; 34 bit--; 35 bin[bit]+=1; 36 } 37 else break; 38 } 39 } 40 41 int div(int base) 42 { 43 int remain=0; 44 int last; 45 for(int i=0;i<102;i=i+3) 46 { 47 last=remain*1000+bin[i]*100+bin[i+1]*10+bin[i+2]; 48 remain=last%base; 49 } 50 if(remain)return 1; 51 else return 0; 52 } 53 54 int printanswer() 55 { 56 int i=0; 57 for(;i<102;i++) 58 { 59 if(bin[i])break; 60 } 61 for(;i<102;i++) 62 printf("%d",bin[i]); 63 64 printf(","); 65 }
把输出的’,’换为换行,看看是不是最高19位数。
其实,11行这里不把大数重置为0也行,毕竟总会有更大的倍数存在。
导出到输出程序:(你要在终端复制过去也行)
./a.out >> L_Print.c //一个>覆盖文本,两个>>追加文本。空文件随意。
输出程序:
1 #include <stdio.h> 2 3 long long answer[202]={0,1,10,111,100,10,1110,1001,1000,111111111,10,11,11100,1001,10010,1110,10000,11101,1111111110,11001,100,10101,110,110101,111000,100,10010,1101111111,100100,1101101,1110,111011,100000,111111,111010,10010,11111111100,111,110010,10101,1000,11111,101010,1101101,1100,1111111110,1101010,10011,1110000,1100001,100,100011,100100,100011,11011111110,110,1001000,11001,11011010,11011111,11100,100101,1110110,1111011111,1000000,10010,1111110,1101011,1110100,10000101,10010,10011,111111111000,10001,1110,11100,1100100,1001,101010,10010011,10000,1111111101,111110,101011,1010100,111010,11011010,11010111,11000,11010101,1111111110,1001,11010100,10000011,100110,110010,11100000,11100001,11000010,111111111111111111,100,101,1000110,11100001,1001000,101010,1000110,100010011,110111111100,1001010111,110,111,10010000,1011011,110010,1101010,110110100,10101111111,110111110,100111011,111000,11011,1001010,10001100111,11101100,1000,11110111110,11010011,10000000,100100001,10010,101001,11111100,11101111,11010110,11011111110,11101000,10001,100001010,110110101,100100,10011,100110,1001,1111111110000,11011010,100010,1100001,11100,110111,11100,1110001,11001000,10111110111,10010,1110110,1010100,10101101011,100100110,100011,100000,11101111,11111111010,1010111,1111100,1111110,1010110,11111011,10101000,10111101,111010,1111011111,110110100,1011001101,110101110,100100,110000,100101111,110101010,11010111,11111111100,1001111,10010,100101,110101000,1110,100000110,1001011,1001100,1010111010111,110010,11101111,111000000,11001,111000010,101010,110000100,1101000101,1111111111111111110,111000011,1000}; 4 5 int main() 6 {Start:; 7 int N; 8 scanf("%d",&N); 9 if(N==0)return 0; 10 printf("%lld\n",answer[N]); 11 goto Start; 12 } 13
如果你把这个打表改成这样去提交是会超时的。想想long long是系统提供的整数,比自己写的渣渣大数不知道高哪里去了。
1 #include <stdio.h> 2 #include <string.h> 3 short bin[102]={0}; 4 5 int main() 6 { 7 int N; 8 int p1(); int div(int base); int printanswer(); 9 Start:; 10 scanf("%d",&N); 11 if(N==0)return 0; 12 // for(int base=1;base<=200;base++) 13 // { 14 memset(bin,0,102*sizeof(short)); 15 while(1) 16 { 17 p1(); 18 if(div(N)==0) 19 { 20 // printf("%d,",base); 21 printanswer(); 22 break; 23 } 24 } 25 // } 26 goto Start; 27 } 28 29 int p1() 30 { 31 int bit=101; 32 bin[101]+=1; 33 while(1) 34 { 35 if(bin[bit]==2) 36 { 37 bin[bit]=0; 38 bit--; 39 bin[bit]+=1; 40 } 41 else break; 42 } 43 } 44 45 int div(int base) 46 { 47 int remain=0; 48 int last; 49 for(int i=0;i<102;i=i+3) 50 { 51 last=remain*1000+bin[i]*100+bin[i+1]*10+bin[i+2]; 52 remain=last%base; 53 } 54 if(remain)return 1; 55 else return 0; 56 } 57 58 int printanswer() 59 { 60 int i=0; 61 for(;i<102;i++) 62 { 63 if(bin[i])break; 64 } 65 for(;i<102;i++) 66 printf("%d",bin[i]); 67 68 printf("\n"); 69 }
这里是本题C队列的简单实现,仅供参考:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 struct LLQueue 6 { 7 long long bin; 8 struct LLQueue *next; 9 }head; 10 struct LLQueue *front=&head; 11 struct LLQueue *back=&head; 12 int push(long long in) 13 { 14 back->next = calloc(1,sizeof(struct LLQueue)); 15 back=back->next ; 16 back->bin = in ; 17 back->next= 0 ; 18 if(front==&head) 19 { 20 front=back; 21 head.next=0; 22 return 1; 23 } 24 return 1; 25 } 26 int pop() 27 { 28 struct LLQueue *p=front; 29 if(front!=back) 30 { 31 front=front->next; 32 free(p); 33 return 1; 34 } 35 else if(front!=&head) 36 { 37 front=back=&head; 38 free(p); 39 return 0; 40 } 41 else return 0; 42 } 43 int cleanQueue() 44 { 45 while(pop()); 46 } 47 48 49 50 int main() 51 {Start:; 52 int N; 53 scanf("%d",&N); 54 if(N==0)return 0; 55 cleanQueue(); 56 push(1); 57 long long tmp=front->bin; 58 while(1) 59 { 60 tmp=front->bin; 61 if( tmp%N==0) 62 { 63 printf("%lld\n",tmp); 64 break; 65 } 66 else 67 { 68 tmp=tmp*10; 69 push(tmp);push(tmp+1); 70 pop(); 71 } 72 } 73 goto Start; 74 }