1. 程式人生 > >常用算法-窮舉法

常用算法-窮舉法

sdn 方法 多少 自身 clas 設置 HR AR 一種可能

窮舉法又稱為枚舉法,它是在計算機算法設計中用得最多的一種編程思想。它的實現方式是:在已知答案範圍的情況下,依次地枚舉該範圍內所有的取值,並對每個取值進行考查,確定是否滿足條件。經過循環遍歷之後,篩選出符合要求的結果來。這種方法充分利用了計算機運算速度快的特點,思路簡單直接,能夠解決大部分的問題。

什麽樣的問題適合使用窮舉法來解決呢?歸納起來,遇到了如下的三種情況,將優先考慮使用窮舉法:

1. 答案的範圍已知:

雖然事先並不知道確切的結果,但能預計到結果會落在哪個取值範圍內。譬如說:

①求1-100之間所有的素數: 無論結果如何,都在1-100的範圍之內。

②求2000-2015年間有幾個月的13號是周日?這15年間共有180個月,月份的個數最多不會超過180

③驗證1000以內的哥德巴赫猜想:即找出1000之內所有的合數,看是否能夠分解為兩個質數之和

。。。。。。

如果仔細觀察,將會發現許多題目的結果範圍都是已知的,都可以使用窮舉法來實現。

2. 答案的結果是離散的,不是連續的。如果要求出1-2之間所有的小數,就無法用窮舉法來實現,因為其結果是無限連續的。

3. 對時間上的要求不嚴格。藍橋杯比賽中的許多題目對於算法的設計是有時間要求的,有時會非常苛刻。如果用窮舉法則耗時過長,不可取。例如求出21位的水仙花數,使用窮舉法可能會花費30分鐘的時間。而藍橋杯試題通常要求時間限制在1秒鐘之內完成,少數會延長至3分鐘。在這種情況下,必須使用新的算法來解決問題。

下面舉個經典的例子:

100塊磚100人來搬,男人一人搬4塊,女人一人搬3塊,小孩3人擡一塊,問男,女,小孩各幾人?

若設男,女,小孩人數分別為X, Y, Z,則只能夠列出兩個等式: X+Y+Z=100 4*X+3*Y+Z/3=100 。三個未知數兩個等式,無法求解。這就只能夠使用窮舉法來實現,具體做法如下:

先確定每種類型人員的數量的取值範圍,由題意可知,男人X的取值範圍是0~100/4=25 女人Y的取值範圍是0~100/3=33 小孩的取值範圍是0~99(必須不大於100且為3的倍數)。使用窮舉法遍歷所有可能的取值結果,逐一判斷篩選出正確的結果。編程如下:

for(int x=0; x<=25; x++)

for(int y=0; y<=33; y++)

for(int z=0; z<=99; z+=3)

if((x+y+z==100)&&(4*x+3*y+z/3==100))

{輸出找到的結果}

如果仔細分析一下,就會發現由於x+y+z==100,那麽只需要考慮x和y的遍歷取值;z值可以通過100-x - y來實現。當然,z值是3的倍數,上述代碼可修改如下:

for(int x=0; x<=25; x++)

for(int y=0; y<=33; y++)

{

int z = 100 - x - y;

if((z%3==0)&&(4*x+3*y+z/3==100))

{輸出找到的結果}

}

從這道題的解決過程中,我們可以發現使用窮舉法的一般過程:

確定需要哪幾個變量,此題需要3個變量x,y, z 如果是其它的題目,所需變量的個數與類型有可能不盡相同,這個要由具體情況而定。

確定每個變量的取值範圍,如上例之中X的範圍是0~25, y的取值範圍是0~33, z的取值範圍是0~33

設置多層的嵌套循環,通常為for循環,最內層之中設置條件判斷,滿足輸出條件時,輸出相關的提示信息。

再來一道可以使用窮舉法解決的問題:

有一群海盜(不多於20人),在船上比拼酒量。過程如下:打開一瓶酒,所有在場的人平分喝下,有幾個人倒下了。再打開一瓶酒平分,又有倒下的,再次重復...... 直到開了第4瓶酒,坐著的已經所剩無幾,海盜船長也在其中。當第4瓶酒平分喝下後,大家都倒下了。 等船長醒來,發現海盜船擱淺了。他在航海日誌中寫到:“......昨天,我正好喝了一瓶.......奉勸大家,開船不喝酒,喝酒別開船......”

請你根據這些信息,推斷開始有多少人,每一輪喝下來還剩多少人。 如果有多個可能的答案,請列出所有答案,每個答案占一行。格式是:人數,人數,...

例如,有一種可能是:20,5,4,2,0

藍橋杯中的許多題目都會提供一個答案的示例,通過分析這個示例可以加深對當前這道題的理解。以本題為例,通過研究示例答案可以看出如下的特點:

(1)答案只可能有4個數,分別代表每輪參與的人數,最後的0是固定的。

(2)每輪的人數是不斷減少的,下一輪只能夠比上一輪人數更少。

(3)每輪人數被1除之後,累加和是1(剛好一瓶酒)

即 1/20+1/5+1/4+1/2=1

根據上述的分析,可以確定如下的變量s1, s2, s3, s4分別代表每輪的人數。

這四個變量的取值範圍分別是 1≤s1≤20 1≤s2≤s1 1≤s3≤s2 1≤s4≤s3 據此來設置4層的嵌套循環,並加上最內層的條件判斷如下:

for(int s1=1; s1<=20; s1++)

for(int s1=1; s1<=20; s1++)

for(int s1=1; s1<=20; s1++)

for(int s1=1; s1<=20; s1++)

if(1/s1+1/s2+1/s3+1/s4==1){輸出結果}

理論上來看是正確的,但實際運行時,由於/運算符在左右兩邊均為整數時,表示整除而不是除法,所以上述的條件判斷需要改寫為更復雜的形式:

(s1*s2*s3+s1*s3*s4+s1*s3*s4+s2*s3*s4)/(s1*s2*s3*s4)==1

根據筆者指導藍橋杯的經驗,至少有三分之一的問題都可以通過窮舉的方法來實現,因此,把窮舉法練習使用好,意義非常重大。

作業:

(1) 換分幣: 將5元的人民幣兌換成1元,5角和1角的硬幣,共有多少種不同的兌換方法?

(2) 找完數: 求1~100內完數的個數。 如果一個數等於它的因子之和,則稱該數為完數(或“完全數”)。例如,6的因子為1,2, 3 而6=1+2+3 , 因此6是完數

(3)找自守數:自守數是指一個數的平方的尾數等於該數自身的自然數。例如:5*5=25; 25*25=625; 76*76=5776; 9376*9376=87909376, 求100000以內的自守數。

鏈接:https://blog.csdn.net/luojin2003529/article/details/49516935

常用算法-窮舉法