我正在尝试解决SPOJ problem "Ones and zeros":
某些正整数的十进制表示仅由1和0组成,并且至少有一位数字,例如101.如果正整数没有这样的属性,可以尝试将其乘以某个正整数,以确定产品是否具有此属性。
我解决这个问题的方法就是做BFS。获取仅包含'1'
的字符串,然后使用它执行BFS,并在每个步骤添加'1'
和'0'
。到目前为止,以字符串形式和余数跟踪数字。当余数为零时,找到了数字。
我的问题是:我的代码对于测试用例来说花费的时间太长,例如9999或99999.如何改善算法的运行时间?
// Shashank Jain
/*
BFS
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
#include <string>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#define LL long long int
using namespace std;
LL n;
string ans;
void bfs()
{
string str,first,second;
str+='1'; // number will start with '1' always
if(n==1)
{
ans=str;
return;
}
queue<pair<string,LL> >q; // pair of STRING(number) and long long int
// (to hold remainder till now)
pair<string,LL>p;
p=make_pair(str,1);
q.push(p);
LL rem,val,temp;
while(q.empty()==0)
{
p=q.front();
q.pop();
str=p.first;
val=p.second;
if(val==0) // remainder is zero means this is number
{
ans=str;
return ;
}
// adding 1 to present number
temp=val*10+1;
rem=(temp)%n;
firstone=str+'1';
p=make_pair(firstone,rem);
q.push(p);
// adding 0 to present number
temp=val*10+0;
rem=(temp)%n;
secondone=str+'0';
p=make_pair(secondone,rem);
q.push(p);
}
}
int main()
{
int t,i;
scanf("%d",&t);
while(t--)
{
scanf("%lld",&n);
bfs();
for(i=0;i<ans.size();i++)
{
printf("%c",ans[i]);
}
printf("\n");
}
return 0;
}
答案 0 :(得分:6)
我刚刚解决了这个问题。我不会发布我的代码片段,但我会说明为什么你的代码更慢
正如sukunrt所说,你需要保持一个大小为n的数组,你可以将当前获得的模数标记为已访问,这样你就不会再访问它了,因为如果你已经访问了模数你不需要考虑直到现在获得的字符串部分,因为它只会使数字更大(我们需要最小值),即它意味着一旦你访问模数你说x
然后你发现最小数字由0组成和除以n。
x
作为余数的1
您总是将如此获得的字符串传递给子节点,这不仅会增加内存,还会增加时间。为避免这种情况,只需再添加两个大小为value[]
和parent[]
的数组。
parent[i]
存储父模数i
。
最后,您可以回溯以形成整数,仅适用于模数= 0. 此外,在进行更改后,您的代码将给WA,因为您必须首先通过在结尾处附加'0'来获得所获得的子项,然后通过在结尾附加'1'来获得子项。 (你可以自己证明)。value[i]
个存储,它是与模数i
对应的当前位(0 <= i
答案 1 :(得分:4)
这是一个提示。以这种方式思考:
假设您想要的数字是X. X mod N = 0。
所以你只需要存储N个状态,即0-n-1。 从1.开始并执行bfs。您需要丢弃与以前具有相同余数的分支。我会把证明留给你。