您的位置:首页 > 其它

POJ1426 建议打表做该题/用数组模拟队列(比STL队列速度要快)

2016-05-18 21:21 435 查看
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
=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

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: