廣度優先搜尋,分支限界- ZOJ - 1136 Multiple
Description
a program that, given a natural number N between 0 and 4999 (inclusively), and M distinct decimal digits X1,X2..XM (at least one), finds the smallest strictly positive multiple of N that has no other digits besides X1,X2..XM (if such a multiple exists).
The input file has several data sets separated by an empty line, each data set having the following format:
On the first line - the number N
On the second line - the number M
On the following M lines - the digits X1,X2..XM.
For each data set, the program should write to standard output on a single line the multiple, if such a multiple exists, and 0 otherwise.
An example of input and output:
Input
22
3
7
0
1
2
1
1
Output
110
0
思路
1、題目一看就是搜尋:把數的組合從小到大一個個嘗試,如果可以是N的倍數,那麼就輸出。
2、要把組合的數從小到大輸出就需要先把數升序排序,然後從小到大依次嘗試,很容易就想到要用廣度優先搜尋(佇列)。
3、如果僅僅是暴力,那麼此題也就僅僅是一個bfs的demo了,但事實不是。此題還需要考慮整數越界的問題,如果N=4999,組合成的數是N的上幾萬倍這時候可能就會越界。(據說使用 long long也可以,但是筆者還是考慮了下)所以要使用string來儲存組合成的整數。那麼如何能夠把問題縮小化呢?很簡單就是儲存餘數。
打個比方:
N=3,t1=10,t2=4。
(t1*10+t2)%N=2 //這是我們一般的處理方式
t1%N=1,(1*10+t2)%N=2 //這是能夠縮小數量級的處理方式
4、num[5010]的設定絕對是程式碼中最巧妙的一點,主要作用是對餘數的判斷。num[i]=1時表示餘數為i的情況已經出現過,num[i]=0時表示餘數為i的情況還沒有出現過。在程式碼中主要有兩個作用:
一、減少重複遍歷。如果出現同樣的餘數,代表在此位置之前已經出現過了這樣的餘數,在此位置之前的定然是更小的數。此題最終結果是找出最小的倍數,所以就沒有必要幫相同的情況放進佇列了。(如果之前更小的數不能得出結果,餘數相同,更大的數也必然得不出結果)
二、避免死迴圈。如果N=2,M=2,X1=3,X2=5。很容易可以明白,這種情況是怎麼都得不到結果的。如果有沒有對重複的餘數的判斷,那麼會一直有數入站,佇列永遠不會空,while也永遠不會結束。但是如果有了餘數這個限制條件,當所有餘數都已經出現過,就不會再有數入佇列,因此當佇列遍歷完的時候,就可以return “0”,表示找不到這個數。
程式碼:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
int n,m;//n為要除以的數,m表示有m個數字組合
int p[12];//p用來儲存m個數
int num[5010];//num[i]=1時表示餘數為i的情況已經出現過,num[i]=0時表示餘數為i的情況還沒有出現過
struct node
{
string s;//表示當前數字的string格式
int res;//當然數字除以n的餘數
};
string bfs()
{
queue<node> q;
for(int i=0; i<m; i++)//先把把每一個數都放進佇列,都只有個位數
{
node ss;
ss.s+=char('0'+p[i]);//把int轉化為數字
ss.res=p[i];
if(ss.s=="0")//數字為0的情況沒意義,直接continue
continue;
q.push(ss);
}
while(!q.empty())
{
node s=q.front();
q.pop();
for(int i=0; i<m; i++)
{
node t;
t.s=s.s+char('0'+p[i]);
t.res=(10*s.res+p[i])%n;
if(num[t.res]==1)//如果此餘數已經出現過,就不放入佇列了
continue;
else
{
num[t.res]=1;//如果上面的情況都不是,表示此數沒有出現過相同的餘數,則進行處理
q.push(t);
}
if(t.res==0)//如果餘數等於0,表示已經找到
return t.s;
}
}
return "0";
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0)//除數等於0沒有意義,直接輸出0
{
printf("0\n");
continue;
}
memset(num,0,sizeof(num));
for(int i=0; i<m; i++)
scanf("%d",p+i);
sort(p,p+m);
cout<<bfs()<<endl;
}
return 0;
}
相關文章
- c++ 廣度優先搜尋(寬搜)C++
- python 二叉樹深度優先搜尋和廣度優先搜尋Python二叉樹
- 基本演算法——深度優先搜尋(DFS)和廣度優先搜尋(BFS)演算法
- 圖的廣度優先搜尋和深度優先搜尋Python實現Python
- js版本的(廣、深)度優先搜尋JS
- BFS廣度優先搜尋(3)--poj2251(zoj1940)(基礎題)
- 【演算法】廣度/寬度優先搜尋(BFS)演算法
- 演算法筆記(廣度優先搜尋)演算法筆記
- 深度和廣度優先搜尋演算法演算法
- 【程式碼隨想錄】廣度優先搜尋
- 演算法競賽——BFS廣度優先搜尋演算法
- 佇列,廣度搜尋-ZOJ 1148 The Game (BFS)佇列GAM
- 廣度優先搜尋(BFS)思路及演算法分析演算法
- 「Golang成長之路」迷宮的廣度優先搜尋Golang
- golang學習筆記——迷宮的廣度優先搜尋Golang筆記
- BFS-圖的廣度優先搜尋--鄰接矩陣矩陣
- 啟發式搜尋的方式(深度優先,廣度優先)和 搜尋方法(Dijkstra‘s演算法,代價一致搜尋,貪心搜尋 ,A星搜尋)演算法
- 演算法(三):圖解廣度優先搜尋演算法演算法圖解
- BFS廣度優先搜尋(10)--fzu2150(基礎題)
- BFS廣度優先搜尋(6)--poj3414(基礎題)
- Swift 演算法實戰之路:深度和廣度優先搜尋Swift演算法
- BFS廣度優先搜尋(11)--hdu2102(基礎題)
- BFS廣度優先搜尋(4)--hdu2717(poj3278)(基礎題)
- 廣度優先搜尋相關面試演算法總結(非圖論方面)面試演算法圖論
- 0演算法基礎學演算法 搜尋篇第二講 BFS廣度優先搜尋的思想演算法
- Android程式設計師面試會遇到的演算法(part 2 廣度優先搜尋)Android程式設計師面試演算法
- 廣度優先遍歷圖解圖解
- 工作安排(dfs深度優先搜尋)
- 【演算法】深度優先搜尋(DFS)演算法
- BFS廣度優先搜尋(5)(亦可以用DFS)--hdu1241(poj1562)(基礎題)
- js實現深度優先遍歷和廣度優先遍歷JS
- Python 圖_系列之基於鄰接炬陣實現廣度、深度優先路徑搜尋演算法Python演算法
- python資料結構之圖深度優先和廣度優先Python資料結構
- 二叉樹的深度優先遍歷和廣度優先遍歷二叉樹
- leetcode 刷題之深度優先搜尋LeetCode
- 深度優先搜尋演算法-dfs講解演算法
- 《圖論》——深度優先搜尋演算法(DFS)圖論演算法
- 【知識點】深度優先搜尋 Depth First Search