版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
廣度優(yōu)先搜索第一頁,共二十四頁,2022年,8月28日廣度優(yōu)先搜索的過程
廣度優(yōu)先搜索算法(又稱寬度優(yōu)先搜索)是最簡便的圖的搜索算法之一,這一算法也是很多重要的圖的算法的原型。Dijkstra單源最短路徑算法和Prim最小生成樹算法都采用了和寬度優(yōu)先搜索類似的思想。廣度優(yōu)先算法的核心思想是:從初始節(jié)點開始,應用算符生成第一層節(jié)點,檢查目標節(jié)點是否在這些后繼節(jié)點中,若沒有,再用產生式規(guī)則將所有第一層的節(jié)點逐一擴展,得到第二層節(jié)點,并逐一檢查第二層節(jié)點中是否包含目標節(jié)點。若沒有,再用算符逐一擴展第二層的所有節(jié)點……,如此依次擴展,檢查下去,直到發(fā)現目標節(jié)點為止。即⒈從圖中的某一頂點V0開始,先訪問V0;⒉訪問所有與V0相鄰接的頂點V1,V2,......,Vt;⒊依次訪問與V1,V2,......,Vt相鄰接的所有未曾訪問過的頂點;⒋循此以往,直至所有的頂點都被訪問過為止。這種搜索的次序體現沿層次向橫向擴展的趨勢,所以稱之為廣度優(yōu)先搜索。第二頁,共二十四頁,2022年,8月28日廣度優(yōu)先搜索算法描述:intbfs(){初始化,初始狀態(tài)存入隊列;隊列首指針head=0;尾指針tail=1;do{
指針head后移一位,指向待擴展結點;
for(inti=1;i<=max;++i)//max為產生子結點的規(guī)則數
{if(子結點符合條件){tail指針增1,把新結點存入列尾;
if(新結點與原已產生結點重復)刪去該結點(取消入隊,tail減1);elseif(新結點是目標結點)輸出并退出;
}}}while(head<tail);//隊列為空}第三頁,共二十四頁,2022年,8月28日廣度優(yōu)先搜索注意事項:1、每生成一個子結點,就要提供指向它們父親結點的指針。當解出現時候,通過逆向跟蹤,找到從根結點到目標結點的一條路徑。當然不要求輸出路徑,就沒必要記父親。
2、生成的結點要與前面所有已經產生結點比較,以免出現重復結點,浪費時間和空間,還有可能陷入死循環(huán)。
3、如果目標結點的深度與“費用”(如:路徑長度)成正比,那么,找到的第一個解即為最優(yōu)解,這時,搜索速度比深度搜索要快些,在求最優(yōu)解時往往采用廣度優(yōu)先搜索;如果結點的“費用”不與深度成正比時,第一次找到的解不一定是最優(yōu)解。
4、廣度優(yōu)先搜索的效率還有賴于目標結點所在位置情況,如果目標結點深度處于較深層時,需搜索的結點數基本上以指數增長。
下面我們看看怎樣用寬度優(yōu)先搜索來解決八數碼問題。例如圖8-1給出廣度優(yōu)先搜索應用于八數碼難題時所生成的搜索樹。搜索樹上的所有結點都標記它們所對應的狀態(tài),每個結點旁邊的數字表示結點擴展的順序。粗線條路徑表明求得的一個解。從圖中可以看出,擴展第26個結點,總共生成46個結點之后,才求得這個解。此外,直接觀察此圖表明,不存在有更短走步序列的解。第四頁,共二十四頁,2022年,8月28日第五頁,共二十四頁,2022年,8月28日【例8.1】圖8-2表示的是從城市A到城市H的交通圖。從圖中可以看出,從城市A到城市H要經過若干個城市?,F要找出一條經過城市最少的一條路線。圖8-2第六頁,共二十四頁,2022年,8月28日【算法分析】看到這圖很容易想到用鄰接距陣來表示,0表示能走,1表示不能走。如圖。
首先想到的是用隊列的思想。a數組是存儲擴展結點的隊列,a[i]記錄經過的城市,b[i]記錄前趨城市,這樣就可以倒推出最短線路。具體過程如下:(1)將城市A入隊,隊首為0、隊尾為1。(2)將隊首所指的城市所有可直通的城市入隊(如果這個城市在隊列中出現過就不入隊,可用一布爾數組s[i]來判斷),將入隊城市的前趨城市保存在b[i]中。然后將隊首加1,得到新的隊首城市。重復以上步驟,直到搜到城市H時,搜索結束。利用b[i]可倒推出最少城市線路。第七頁,共二十四頁,2022年,8月28日【參考程序】#include<iostream>#include<cstring>usingnamespacestd;intju[9][9]={{0,0,0,0,0,0,0,0,0},{0,1,0,0,0,1,0,1,1},{0,0,1,1,1,1,0,1,1},{0,0,1,1,0,0,1,1,1},{0,0,1,0,1,1,1,0,1},{0,1,1,0,1,1,1,0,0},{0,0,0,1,1,1,1,1,0},{0,1,1,1,0,0,1,1,0},{0,1,1,1,1,0,0,0,1}};inta[101],b[101];bools[9];//初始化intout(intd)//輸出過程{cout<<char(a[d]+64);while(b[d]){d=b[d];cout<<"--"<<char(a[d]+64);}cout<<endl;}第八頁,共二十四頁,2022年,8月28日voiddoit(){inthead,tail,i;head=0;tail=1;//隊首為0、隊尾為1a[1]=1;//記錄經過的城市
b[1]=0;//記錄前趨城市
s[1]=1;//表示該城市已經到過
do//步驟2{head++;//隊首加一,出隊
for(i=1;i<=8;i++)//搜索可直通的城市
if((ju[a[head]][i]==0)&&(s[i]==0))//判斷城市是否走過
{tail++;//隊尾加一,入隊
a[tail]=i;
b[tail]=head;s[i]=1;if(i==8){out(tail);head=tail;break;//第一次搜到H城市時路線最短
}}}while(head<tail);}intmain()//主程序{memset(s,false,sizeof(s));doit();//進行Bfs操作
return0;}第九頁,共二十四頁,2022年,8月28日【例8.2】一矩形陣列由數字0到9組成,數字1到9代表細胞,細胞的定義為沿細胞數字上下左右還是細胞數字則為同一細胞,求給定矩形陣列的細胞個數。如:陣列4100234500067103456050020456006710000000089有4個細胞?!舅惴ǚ治觥竣艔奈募凶x入m*n矩陣陣列,將其轉換為boolean矩陣存入bz數組中;
⑵沿bz數組矩陣從上到下,從左到右,找到遇到的第一個細胞;
⑶將細胞的位置入隊h,并沿其上、下、左、右四個方向上的細胞位置入隊,入隊后的位置bz數組置為flase;⑷將h隊的隊頭出隊,沿其上、下、左、右四個方向上的細胞位置入隊,入隊后的位置bz數組置為flase;
⑸重復4,直至h隊空為止,則此時找出了一個細胞;
⑹重復2,直至矩陣找不到細胞;
⑺輸出找到的細胞數。
第十頁,共二十四頁,2022年,8月28日【參考程序】#include<cstdio>usingnamespacestd;intdx[4]={-1,0,1,0},
dy[4]={0,1,0,-1};intbz[100][100],num=0,n,m;voiddoit(intp,intq){intx,y,t,w,i;inth[1000][2];num++;bz[p][q]=0;t=0;w=1;h[1][1]=p;h[1][2]=q;//遇到的第一個細胞入隊
do{t++;//隊頭指針加1for(i=0;i<=3;i++)//沿細胞的上下左右四個方向搜索細胞
{x=h[t][1]+dx[i];y=h[t][2]+dy[i];
if((x>=0)&&(x<m)&&(y>=0)&&(y<n)&&(bz[x][y]))//判斷該點是否可以入隊
{w++;h[w][1]=x;h[w][2]=y;bz[x][y]=0;
}//本方向搜索到細胞就入隊
}}while(t<w);//直至隊空為止}第十一頁,共二十四頁,2022年,8月28日intmain(){inti,j;chars[100],ch;scanf("%d%d\n",&m,&n);
for(i=0;i<=m-1;i++)for(j=0;j<=n-1;j++)bz[i][j]=1;//初始化
for(i=0;i<=m-1;i++)
{gets(s);for(j=0;j<=n-1;j++)if(s[j]=='0')bz[i][j]=0;}for(i=0;i<=m-1;i++)for(j=0;j<=n-1;j++)if(bz[i][j])doit(i,j);//在矩陣中尋找細胞
printf("NUMBERofcells=%d",num);return0;}第十二頁,共二十四頁,2022年,8月28日【例8.3】最短路徑(1995年高中組第4題)如下圖所示,從入口(1)到出口(17)的可行路線圖中,數字標號表示關卡?,F將上面的路線圖,按記錄結構存儲如下圖6:請設計一種能從存儲數據中求出從入口到出口經過最少關卡路徑的算法。第十三頁,共二十四頁,2022年,8月28日【算法分析】
該題是一個路徑搜索問題,根據圖示,從入口(1)到出口(17)可能有多條途徑,其中最短的路徑只有一條,那么如何找最短路徑呢?根據題意,用數組no存儲各關卡號,用數組per存儲訪問到某關卡號的前趨關卡號。其實本題是一個典型的圖的遍歷問題,我們可以采用圖的廣度優(yōu)先遍歷,并利用隊列的方式存儲頂點之間的聯系。從入口(1)開始先把它入隊,然后把(1)的所有關聯頂點都入隊,即訪問一個頂點,將其后繼頂點入隊,并存儲它的前趨頂點,……,直到訪問到出口(17)。最后,再從出口的關卡號(17)開始回訪它的前趨關卡號,……,直到入口的關卡號(1),則回訪的搜索路徑便是最短路徑。從列表中可以看出出口關卡號(17)的被訪問路徑最短的是:(17)←(16)←(19)←(18)←(1)由此,我們得到廣度優(yōu)先遍歷求最短路徑的基本方法如下:假設用鄰接矩陣存放路線圖(a[i][j]=1表示I與j連通,a[i][j]=0表示i與j不連通)。再設一個隊列和一個表示拓展到哪個頂點的指針變量pos。(1)從入口開始,先把(1)入隊,并且根據鄰接矩陣,把(1)的后繼頂點全部入隊,并存儲這些后繼頂點的前趨頂點為(1);再把pos后移一個,繼續(xù)拓展它,將其后繼頂點入隊,并存儲它們的前趨頂點,……,直到拓展到出口(目的地(17));
第十四頁,共二十四頁,2022年,8月28日
注意后繼頂點入隊前,必須要檢查這個頂點是否已在隊列中,如果已經在了就不要入隊了;這一步可稱為圖的遍歷或拓展;(2)從隊列的最后一個關卡號(出口(17))開始,依次回訪它的前驅頂點,倒推所得到的路徑即為最短路徑。主要是依據每個頂點的前趨頂點倒推得到的。實現如下:
i=1;
while(no[i]!=17)++i;do{cout<<"("<<no[i]<<")";
cout<<"←";i=pre[i];}while(I!=0);【參考程序】留給同學們完成,文件名ex8_3.cpp。第十五頁,共二十四頁,2022年,8月28日【例8.4】迷宮問題如下圖所示,給出一個N*M的迷宮圖和一個入口、一個出口。編一個程序,打印一條從迷宮入口到出口的路徑。這里黑色方塊的單元表示走不通(用-1表示),白色方塊的單元表示可以走(用0表示)。只能往上、下、左、右四個方向走。如果無路則輸出“noway.”。入口→0-1000000-10000-1000-1-100000-1-1-100-1-100000→出口0000000-1-1【算法分析】只要輸出一條路徑即可,所以是一個經典的回溯算法問題,本例給出了回溯(深搜)程序和廣搜程序。實現見參考程序。第十六頁,共二十四頁,2022年,8月28日【深搜參考程序】#include<iostream>usingnamespacestd;intn,m,desx,desy,soux,souy,totstep,a[51],b[51],map[51][51];boolf;intmove(intx,inty,intstep){map[x][y]=step;//走一步,作標記,把步數記下來
a[step]=x;b[step]=y;//記路徑
if((x==desx)&&(y==desy)){f=1;totstep=step;}else{if((y!=m)&&(map[x][y+1]==0))move(x,y+1,step+1);//向右
if((!f)&&(x!=n)&&(map[x+1][y]==0))move(x+1,y,step+1);//往下
if((!f)&&(y!=1)&&(map[x][y-1]==0))move(x,y-1,step+1);//往左
if((!f)&&(x!=1)&&(map[x-1][y]==0))move(x-1,y,step+1);//往上
}}第十七頁,共二十四頁,2022年,8月28日intmain(){inti,j;cin>>n>>m;//n行m列的迷宮
for(i=1;i<=n;i++)//讀入迷宮,0表示通,-1表示不通
for(j=1;j<=m;j++)cin>>map[i][j];
cout<<"inputtheenter:";cin>>soux>>souy;//入口
cout<<"inputtheexit:";cin>>desx>>desy;//出口
f=0;//f=0表示無解;f=1表示找到了一個解
move(soux,souy,1);if(f){for(i=1;i<=totstep;i++)//輸出直迷宮的路徑
cout<<a[i]<<","<<b[i]<<endl;}elsecout<<"noway."<<endl;return0;}第十八頁,共二十四頁,2022年,8月28日【廣搜參考程序】#include<iostream>usingnamespacestd;intu[5]={0,0,1,0,-1},w[5]={0,1,0,-1,0};intn,m,i,j,desx,desy,soux,souy,head,tail,x,y,a[51],b[51],pre[51],map[51][51];boolf;intprint(intd){if(pre[d]!=0)print(pre[d]);//遞歸輸出路徑
cout<<a[d]<<","<<b[d]<<endl;}intmain(){inti,j;cin>>n>>m;//n行m列的迷宮
for(i=1;i<=n;i++)//讀入迷宮,0表示通,-1表示不通
for(j=1;j<=m;j++)cin>>map[i][j];
cout<<"inputtheenter:";cin>>soux>>souy;//入口
cout<<"inputtheexit:";cin>>desx>>desy;//出口
head=0;
tail=1;第十九頁,共二十四頁,2022年,8月28日
f=0;map[soux][souy]=-1;a[tail]=soux;b[tail]=souy;pre[tail]=0;while(head!=tail)//隊列不為空
{head++;for(i=1;i<=4;i++)//4個方向
{x=a[head]+u[i];y=b[head]+w[i];
if((x>0)&&(x<=n)&&(y>0)&&(y<=m)&&(map[x][y]==0)){//本方向上可以走
tail++;a[tail]=x;b[tail]=y;pre[tail]=head;map[x][y]=-1;if((x==desx)&&(y==desy))//擴展出的結點為目標結點
{f=1;print(tail);break;}}}if(f)break;}if(!f)cout<<"noway."<<endl;return0;}
第二十頁,共二十四頁,2022年,8月28日輸入1:輸出1:輸入2:輸出2:85-1-1-1-1-10000-1-1-1-10-1-1000-1-100-1-1-1000-1-1-1-10-1-1000-121842,12,22,32,43,44,44,35,36,385-1-1-1-1-10000-1-1-1-10-1-1000-1-100-1-1-1000-1-1-1-1-1-1-1000-12184noway.第二十一頁,共二十四頁,2022年,8月28日【上機練習】1、面積(area)編程計算由“*”號圍成的下列圖形的面積。面積計算方法是統(tǒng)計*號所圍成的閉合曲線中水平線和垂直線交點的數目。如下圖所示,在10*10的二維數組中,有“*”圍住了15個點,因此面積為15。00000000000000***0000000*00*
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度設施農業(yè)種植與銷售合同3篇
- 2025農村自建房綠色建材采購與應用合同
- 二零二五年度兼職業(yè)務員客戶滿意度調查合同3篇
- 2025年度公司解除與因自然災害影響員工勞動合同證明3篇
- 二零二五年度環(huán)保材料研發(fā)與應用股東合伙人協(xié)議3篇
- 2025技術培訓合同范本
- 2025年度創(chuàng)意產業(yè)園區(qū)商鋪租賃管理協(xié)議3篇
- 2025年度礦山礦產資源勘查與開發(fā)利用合作協(xié)議3篇
- 二零二五年度地質勘探駕駛員聘用合同協(xié)議書3篇
- 二零二五年度市政工程機械租賃與施工合同3篇
- 芳療與中醫(yī)課件
- 醫(yī)院護工培訓-教學課件
- 考研考博-英語-中國礦業(yè)大學(北京)考試押題卷含答案詳解
- 欄桿百葉安裝施工方案
- 低壓配電電源質量測試記錄
- 安徽省水利工程質量檢測和建筑材料試驗服務收費標準
- 2022課程標準解讀及學習心得:大單元教學的實踐與思考
- OA協(xié)同辦公系統(tǒng)運行管理規(guī)定
- 某小區(qū)建筑節(jié)能保溫工程監(jiān)理實施細則
- 污水處理中常用的專業(yè)術語
- 外市電引入工程實施管理要求(重要)
評論
0/150
提交評論