1. 程式人生 > >捕牛記(1503)解題報告(bfs)

捕牛記(1503)解題報告(bfs)

字節數 first 檢測 表示 所有結點 sca c++ fin ++

解題思路:每到一個坐標點都有三種走法,每個點只走一次,直到第一次發現牛的坐標為止。用廣度優先搜索(Breadth First Search)(bfs)

代碼實現:定義一個標記結點狀態的數組、一個記錄結點的值的數組、一個隊列,將一開始John的坐標視為源結點,將除了源結點外的所有結點(即坐標)的狀態標記為0,源結點的狀態標記為1,因為該結點已被發現,同時將源結點的值(即到達該結點的時間)初始化為0。再將隊列進行初始化,該隊列的初始狀態僅包含源結點。接下來進行循環,直到隊列為空時結束:每次循環時,將隊頭的結點(視為父結點)取出,將其從隊列中刪除。再對該父結點的每個子結點(即每種移動方式所到達的結點)進行考察,若子結點的狀態為0(即未被發現),則將其狀態標記為1(表示已發現),同時將該子結點的值(即到達該結點的時間)設置為父結點的值+1,再將其插入隊列的末尾。每次進行循環前,對牛所在結點的值進行判斷,若不是初值(初值被置為-1),則表明該結點已被發現,無須再循環。

具體代碼:本代碼采用簡潔的縮進表示方法,同時將具有關聯意義的語句寫在一行,具體請看代碼:

 1 /*
 2 Language:C/C++
 3 Time:163ms
 4 Memory:1384k
 5 */
 6 
 7 #include<stdio.h>
 8 #include<string.h>
 9 #define D 100001 //請先看主函數的代碼
10 #define E if(b>=0&&b<D&&sta[b]==0){ /*判斷子結點b是否超越坐標範圍及入隊狀態*/ 11               sta[b]=1,val[b]=val[f]+1
; /*標記b已入隊,其值為父結點的值加1*/ 12 que[tail]=b; /*將b插入隊列*/ 13 tail++;if(tail==D) tail=0;} //隊尾後移,同時判斷隊尾是否需要循環 14 int main() 15 { 16 int n,k,f,b,val[D],que[D],head,tail;/*定義了隊列的隊頭結點(父結點)(front),子結點(back), 17 結點的值(value)數組(用於存放到達結點(即坐標)的時間),一個隊列(queue)及隊頭(head)隊尾(tail)*/ 18 char
sta[D];//定義了一個結點(即坐標)的入隊狀態(state)數組,因為只需要標記0或1,,故用字節數最小的char類型 19 while(scanf("%d%d",&n,&k)&&n!=-1&&k!=-1){ 20 val[k]=-1; //假設到達牛所在坐標的時間為-1(即結點k的值為-1) 21 memset(sta,0,sizeof(sta)); //將所有坐標點的入隊狀態用0標記,表示未入隊 22 sta[n]=1,val[n]=0; //初始化,標記John的坐標n已入隊,到達n的時間為0 23 que[0]=n,head=0,tail=1; //將n插入隊列,此時隊頭的值為0,隊尾的值為1 24 while(head!=tail&&val[k]==-1){ //當隊頭不等於隊尾(即隊列不為空)及k的值未被改變時,執行循環 25 f=que[head]; //取出隊列的隊頭結點f 26 head++;if(head==D) head=0; //隊頭後移,同時判斷隊頭是否需要循環 27 b=f+1;E //以下三行用於檢測f的三個子結點b 28 b=f-1;E 29 b=2*f;E} 30 printf("%d\n",val[k]);} 31 return 0; 32 }

捕牛記(1503)解題報告(bfs)