題目大意
給出一個整數。
求出任意一個它的倍數m,要求m必須只由十進制的 0 或 1 組成。
思路分析
首先暴力枚舉肯定是不可能的 1000ms 想不超時都難,而且枚舉還要解決大數問題。
解題方法: BFS|DFS+同餘模定理
我以 爲例
首先十進制數,開頭第一個數字(最高位)一定不能爲0,即最高位必爲 1
設6的 “01十進制倍數” 爲k,那麼必有 ,現在就是要用求k值:
1、先搜索的最高位,最高位必爲1,則此時 k=1,但 1%6 = 1 != 0
因此 k=1 不是所求,存儲餘數 1
2、搜索下一位,此時有兩種可能:
下一位可能爲 0,即 ,此時 ,那麼
可能爲 1,即 ,此時 ,那麼
由於餘數均不爲0,即 與 均不是所求
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;
}