0)
题意:
求一个数的(任意一个)倍数,并且这个倍数仅由0和1组成。
分析:
深搜所有0、1组成的数,直到出现所求数的倍数。
①题目中说 The decimal representation of m must not contain more than 100 digits.看起来很吓人,结果证明只算long long int的最大范围内(10^19之内)的由0、1组成的数就可以AC。当然,bfs或者dfs都可以,不过bfs要自己写数组模拟queue,否则会超时(C++下),而dfs注意及时回溯(以防止数大于Longlong),可以再用同余模定理做一下优化或者不做优化。
②其中。对于数组模拟队列的bfs,用一个数组存储出现的余数,然后用该数组以及下标/2来模拟bfs队列,用下标%2==0或者==1来代表在这一层所得到的数后面+0还是+1。问题是,那么从1、10、11、 100、 101、 110、 111...直到出现该数的由0、1组成的倍数,中间最多要经过多少余数的存储呢,虽然后来证明是524286,但事先恐怕不好预算,得先打表看看哪个余数最长,但为了余数的上限而去打表太麻烦了,还不如高精度+队列直接线下把答案打表,所以贴③的代码,只是学习一下用数组和下标%2,来模拟bfs双入口即可。
③因为n是1到200,所以最后还是推荐直接用大数的高精度除法和bfs来对答案进行打表;也可以直接将答案输到数组,然后粘到程序里查询AC...;当然,如果发现最长的数不超过20位,那就也可以用深搜或广搜+long long 过。
1)
简单深搜,及时回溯防止溢出,在不知道上限的情况下,也是水过
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
bool found;
void DFS(unsigned __int64 t ,int n,int k)
{
if(found)
return ;//如果已经发现了答案就没搜的必要了
if(t%n==0)
{//发现答案,输出,标记变量该true
printf("%I64u\n",t);
found=true;
return ;
}
if(k==19)//到第19层,回溯(以防止数大于10^19就超过了long long 范围了)
return ;
DFS(t*10,n,k+1); //搜索×10
DFS(t*10+1,n,k+1); //搜索×10+1
}
int main()
{
int n;
while(cin>>n,n)
{
found=false;//标记变量,当为true代表搜到了题意第一的m
DFS(1,n,0); //从1开始搜n的倍数,第三个参数代表搜的层数,当到第19层时返回(因为第20层64位整数存不下)
}
return 0;
}
2)
广搜+long long,C++会报超时(g++AC)(但是用数组模拟queue就可以过如下面③,于是是不是佐证了STL比数组的效率低呢)
#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
void bfs(int n)
{
queue<long long>q;
q.push(1);
while(!q.empty())
{
int i;
long long x;
x=q.front();
q.pop();
if(x%n==0)
{
printf("%lld\n",x);
return ;
}
q.push(x*10);
q.push(x*10+1);
}
}
int main()
{
int n;
while(scanf("%d",&n)&&n)
{
bfs(n);
}
return 0;
}
广搜+string,因为同样用了STL的队列,C++下超时
#include<iostream>
#include<string>
#include<iomanip>
#include<algorithm>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
using namespace std;
struct Node{
int mod;
string ans;
}node,nn[210];
void bfs(int n){
queue <Node> q; //
struct Node now;
now.mod=1%n;
now.ans="1";
q.push(now);
while(!q.empty()){
now=q.front();
q.pop();
if(now.mod%n==0){
nn[n]=now;
return ;
}
struct Node next1;
struct Node next2;
next1.mod=(now.mod*10)%n;
next1.ans=now.ans+"0";
q.push(next1);
next2.mod=(now.mod*10+1)%n;
next2.ans=now.ans+"1";
q.push(next2);
}
}
int main()
{
int k;
nn[1].ans="1";
for(int i=2;i<=200;i++){
if(i%2==0){
nn[i].ans=nn[i/2].ans+"0";
}
else
bfs(i);
}
while(cin>>k&&k!=0){
cout<<nn[k].ans<<endl;
}
}
3)这个就是用数组模拟了STL中的queue了,仅仅学习代码中如何用数组模拟队列进行bfs广搜即可,因为mod的大小不容易确定,所以这种做法我认为不适合这道题。(我还是觉得打表比较适合这道题...)
//Memory Time
//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;
}
4)
Description
Input
Output
Sample Input
2 6 19 0
Sample Output
10 100100100100100100 111111111111111111