一个隐藏的bfs搜索

...还是要加油啊...

通常,我们用bfs来解决最短路径问题。一般与图联合出现。但是,bfs,dfs也可以用来解决数学中的问题。

例如下面这题:


问题 L: 寻找倍数

时间限制: 2.000 Sec  内存限制: 512 MB
提交 状态

题目描述

给定一个正整数n,编写一个程序来找出n的一个非零倍数m,其十进制表示仅包含数字0和1。你可以假设n不大于998,并且存在一个相应的m,其十进制位数不超过100位。

输入

输入包含多个测试用例。每行包含一个n的值(1 <= n <= 998),遇到0输入结束。

输出

对于输入中的每个n值,打印一行包含对应的最小的m的值。

样例输入 Copy
2
6
19
0
样例输出 Copy
10
1110
11001

这题我一开始看,就以为是个抽象的数论问题,就给跳了...(下次再也不了www)不过,细想这题的状态,每个结果都只能由 0 1 构成,那不就是,每个数在之前的前提下,×10或×10+1 嘛?这样一来,前后推导关系就出来了,自然就好想了。

但还有一个问题,就是这个“不超过100位”。我们肯定不能用long long来存储每次的结果,那自然要用到字符串。但高精度除法又太麻烦...这时我们注意到,这题只要判断 是否能整除 即可,那么,余数的性质能很好的满足这一点。例如,求一个10000位的字符串a整除数b的余数,程序可以写成:

string a;
int b;
int t=0;
for(auto i:a){
    t=(t+(i-'0')*10)%b;
}
//t即为要求的余数。

那么,我们就可以将程序写成:

#include<iostream>
#include<queue>
using namespace std;
int n;
void bfs(){
    queue<string>a;
    a.push("1");
    while(!a.empty()){
        string num=a.front();a.pop();
        int t=0;
        for(auto g:num){
            t=(t*10+g-'0')%n;
        }
        if(t==0){
            cout<<num<<'\n';
            return ;
        }else{
            a.push(num+'0');
            a.push(num+'1');
        }
    }
}
int main()
{
    while(scanf("%d",&n),n){
        bfs();
    }
    return 0;
} 

这样写自然是可以过的,不过如果不开o3优化,就会TLE。那么,如何优化呢?

我们平常写bfs的时候,其实都会判断此时用到的数是否走过,走过就不走。那么这题也是这个道理。可以用一个 unordered_set来存储每个用过的余数,用其count()函数来判断此时的字符串是否重复。

代码如下:

#include<iostream>
#include<queue>
#include<unordered_set>
using namespace std;
int n;
void bfs(){
    queue<string>a;
    unordered_set<int>u;
    a.push("1");
    while(!a.empty()){
        string num=a.front();a.pop();
        int t=0;
        for(auto g:num){
            t=(t*10+g-'0')%n;
        }
        if(t==0){
            cout<<num<<'\n';
            return ;
        }else if(!u.count(t)){
            a.push(num+'0');
            a.push(num+'1');
            u.insert(t);
        }
    }
}
int main()
{
    while(scanf("%d",&n),n){
        bfs();
    }
    return 0;
} 

其中,为什么要判断每个 余数 是否用过呢?因为两个余数相同的数 经过相同的变换 余数仍相同

下面粘自AI:

如果两个数在被m除时的余数相同,‌那么无论我们对这两个数进行何种相同的运算或变化,‌它们在被m除时的余数仍然相同。‌这表明同余关系在数学运算中具有稳定性,‌确保了余数相同的两个数经历相同变化后余数依然相同。‌

综上所述,其实我觉得本题的核心点是想到 每个状态可以再往下分为两个状态 ,进而想到bfs算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值