POJ 1426 Find The Multiple【題解報告|DFS|BFS|模運算】

題目大意

給出一個整數n(1<=n<=200)n (1 <= n <= 200)

求出任意一個它的倍數m,要求m必須只由十進制的 0 或 1 組成。

思路分析

首先暴力枚舉肯定是不可能的 1000ms 想不超時都難,而且枚舉還要解決大數問題。

解題方法: BFS|DFS+同餘模定理


我以 n=6n=6 爲例

首先十進制數,開頭第一個數字(最高位)一定不能爲0,即最高位必爲 1

設6的 “01十進制倍數” 爲k,那麼必有 k%6=0k\%6 = 0 ,現在就是要用BFSDFSBFS|DFS求k值:

1、先搜索kk的最高位,最高位必爲1,則此時 k=1,但 1%6 = 1 != 0
 因此 k=1 不是所求,存儲餘數 1

2、搜索下一位,此時有兩種可能:
  下一位可能爲 0,即 k10+0k*10+0,此時 k=10k=10,那麼 k%6=4k\%6=4
  可能爲 1,即 k10+1k*10+1,此時 k=11k=11,那麼 k%6=5k\%6=5
 由於餘數均不爲0,即 k=10k=10k=11k=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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章