题目大意
给出一个整数 n ( 1 < = n < = 200 ) n (1 <= n <= 200) n(1<=n<=200)。
求出任意一个它的倍数m,要求m必须只由十进制的 0 或 1 组成。
思路分析
首先暴力枚举肯定是不可能的 1000ms 想不超时都难,而且枚举还要解决大数问题。
解题方法: BFS|DFS+同余模定理
我以 n = 6 n=6 n=6 为例
首先十进制数,开头第一个数字(最高位)一定不能为0,即最高位必为 1
设6的 “01十进制倍数” 为k,那么必有 k % 6 = 0 k\%6 = 0 k%6=0 ,现在就是要用 B F S ∣ D F S BFS|DFS BFS∣DFS求k值:
1、先搜索
k
k
k的最高位,最高位必为1,则此时 k=1,但 1%6 = 1 != 0
因此 k=1 不是所求,存储余数 1
2、搜索下一位,此时有两种可能:
下一位可能为 0,即
k
∗
10
+
0
k*10+0
k∗10+0,此时
k
=
10
k=10
k=10,那么
k
%
6
=
4
k\%6=4
k%6=4
可能为 1,即
k
∗
10
+
1
k*10+1
k∗10+1,此时
k
=
11
k=11
k=11,那么
k
%
6
=
5
k\%6=5
k%6=5
由于余数均不为0,即
k
=
10
k=10
k=10 与
k
=
11
k=11
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两种选择,换而言之是一个双入口BFS,当然这道题没有让我们求位数最少的,因此我们也可以使用带深度约束的dfs进行操作,dfs的实现更简便一些。
dfs:
//164K 313MS
int n;
string t, res;
bool dfs(int mod) {
if (t.size() > 100)return false;//有深度限制的dfs
else if (mod == 0) { res = t; return true; }
t += '0';
if(dfs((mod * 10) % n))
return true;
t.erase(t.size() - 1, 1);
t += '1';
if(dfs((mod * 10 + 1) % n))
return true;
t.erase(t.size() - 1, 1);
return false;
}
int main() {
while (scanf("%d", &n) && n) {
t.clear(); res.clear();
t += '1';
dfs(1);
cout << res << endl;
}
}
bfs:
//2236K 32MS
#include<iostream>
using namespace std;
int mod[524286]; //保存每次mod n的余数
//由于198的余数序列是最长的
//经过反复二分验证,436905是能存储198余数序列的最少空间
//但POJ肯定又越界测试了...524286是AC的最低下限,不然铁定RE
int main(int i)
{
int n;
while(cin>>n)
{
if(!n)
break;
mod[1]=1%n; //初始化,n倍数的最高位必是1
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)
cout<<mod[--pm]; //倒序输出
cout<<endl;
}
return 0;
}