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