首页 > 代码库 > 捕牛记(1503)解题报告(bfs)

捕牛记(1503)解题报告(bfs)

解题思路:每到一个坐标点都有三种走法,每个点只走一次,直到第一次发现牛的坐标为止。用广度优先搜索(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)