广度优先遍历队列实现

来源:互联网 发布:淘宝客服部门奖罚制度 编辑:程序博客网 时间:2024/05/22 01:50

本周做了两道题,Fast Robot和Picking up Jewels

先说Fast Robot,要求找出从起点到终点最少拐弯次数。

这道题其实有一种很简单的算法:

1.      从起点开始,将拐1次弯的点全部入队,map[i][j].path全部标记成1(并且标记为已访问),然后起点出队。

2.      拐一次弯的第一个点出队,将第一个点作为起点,所有拐一次弯并且未入队的点入队,即总计拐两次弯的点入队。以此类推,直到将所有的拐一次弯的点全部出队。

3.      同理所有的可以走到的点都会入队出队,直到找到终点。

在此原理的基础上,只要找到了终点,那就是最短的拐弯次数。

 

         可是做的时候并没有去思考过多,上来就用了特别朴素的方法,也特别复杂。换了好几次尝试,从不用指针实现的队到用指针实现的队,最后又换回了不用指针实现的队。

首先 

int DIR[4][2] ={{-1,0},{0,1},{1,0},{0,-1}};   //正点方向顺时针 上右下左

void BFS(Node start, Node end) {Node t1;enqueue(start); // 将起始点进队int newValue = 0;int i;int dx = 0, dy = 0;while(!isEmpty()) {  // 如果队不为空t1 = dequeue();  // 出队for(i=0; i<4; i++)  //扫描当前节点的4个方向{dx = t1.x+DIR[i][0];dy = t1.y+DIR[i][1];if(dx == end.x && dy == end.y){if(t1.dir != i)   //如果当前节点方向与即将要前进的方向(到终点)不一致,则拐弯数+1{Answer = Answer<t1.value+1?Answer:t1.value+1;  //比较新的路径的拐弯数和当前所记录的最小值,取小的数} else {Answer  = Answer<t1.value?Answer:t1.value;}#ifdef TESTcout<<"find end!:"<<dx<<","<<dy<<", Answer = "<<Answer<<endl;printOMap();#endifcontinue;  // 终点不进队,所以用continue}if(dx>=0 && dy>=0 && dx<N && dy<M && map[dx][dy].d=='0')  // '0'表示可走的路{if(t1.dir != i)           //如果当前节点方向与即将要前进的方向不一致,则拐弯数+1{newValue = t1.value+1;}else {newValue = t1.value;}if(map[dx][dy].dir == -1 || newValue<=map[dx][dy].value) {   //如果 要判断的点是从没访问过的点  或者  已经访问过但是新的路径拐弯次数少于之前保存的拐弯次数   map[dx][dy].dir = i;   // 将所判断的点的方向置为当前行进方向map[dx][dy].value = newValue;   // 将所判断的点的拐弯书置为新的路径拐弯次数enqueue(map[dx][dy]);   // 进队  这里本来是要用指针来实现的,但是因为本题设计到拐弯数和方向两个变量调控的原因,    // 只保存一个值的话会有问题。除非添加多个方向的变量,否则最好是使用拷贝的方式进队}}}}}

我是那种建模想象能力不太好的人,一般都需要画出图来理解,所以我test的方式是把整个map当前的状态绘制了出来。

void printOMap(){cout<<"---------------------N="<<N<<",M="<<M<<endl;int i,j;for(i=0; i<N; i++){for(j=0; j<M; j++){if(map[i][j].value == BMAX){cout<<"*"<<" ";}else{        cout<<map[i][j].value<<" ";}}cout<<endl;}}


7 7   // 7列7行

1 2 7 5  // start end

1111111  // 1是墙,0是路

0000011

1011001

1011100

1011110

1000000

1111111

find end!:4,6, Answer = 5

---------------------N=7,M=7

* * * * * * *

1 0 0 0 0 * *

* 1 * * 1 2 *

* 1 * * * 3 4

* 1 * * * * -1

* 1 2 2 2 * *

* * * * * * *

find end!:4,6, Answer = 3

---------------------N=7,M=7

* * * * * * *

1 0 0 0 0 * *

* 1 * * 1 2 *

* 1 * * * 3 4

* 1 * * * * -1

* 1 2 2 2 2 2

* * * * * * *

因此最小的拐弯数就是3了。

       在做这道题的时候,我曾遇到一个百思难得其解的问题。就是小的数据运算结果都是OK的,但是一碰到大的数据的时候,DFS后的数组输出就有问题了。



100x120的数据为什么输出变成了7行1列呢。研究了半天没整明白。最后在老大的帮助下,发现原来我的循环队列写成了顺序队列,40000的长度都没打住,把N和M的空间给踩了,可见这复杂的。也由此暴露出来了一个问题,这基础多不牢固能犯这错误,哈哈。

现在来说说队列怎么写吧。

typedef struct {int x;int y;int dir;int value;char d;}Node;  // 节点结构体Node map[MAX][MAX];  // 节点数组用于存储maptypedef struct {Node data[LENGTH];int rear;int front;}Queue;  // 队列结构体Queue que;   // 队列

Node map[MAX][MAX];  输入是char型的字符,那么怎么存储成Node的数组呢

如果是char map[MAX][MAX],那么你可以这样

for(i=0; i<N; i++) {

cin>>map[i];

}

然而Node型的你则需要逐个地输入了。

for(i=0; i<N; i++){    for(j=0; j<M; j++)    {        cin>>map[i][j].d;        map[i][j].x = i;        map[i][j].y = j;        map[i][j].dir = -1;        map[i][j].value = 999999;    }}

队列一般需要队空、队满、入队、出队、获取对头、初始化等方法。

bool isEmpty(){    if(que.rear == que.front){        return true;    }else {        return false;    }}bool isFull(){    if((que.rear+1)%LENGTH == que.front){        return true;    }else {        return false;    }}void enqueue(Node n){#ifdef QLOG    cout<<"enqueue:"<<n.x<<","<<n.y<<",dir = "<<n.dir<<",value = "<<n.value<<endl;#endif    if(!isFull())    {        que.data[que.rear] = n;        que.rear = (que.rear+1)%LENGTH;        // que.rear++;   // 顺序队列    } else {    #ifdef QLOG    cout<<"enqueue fail because queue is full"<<endl;#endif    }    }Node dequeue(){    Node n = que.data[que.front];    if(!isEmpty())    {        que.front = (que.front+1)%LENGTH;        //que.front++;  // 顺序队列#ifdef QLOG        cout<<"dequeue:"<<n.x<<","<<n.y<<",dir = "<<n.dir<<",n.value = "<<n.value<<endl;#endif    } else {#ifdef QLOG        cout<<"Queue is empty"<<endl;#endif    }    return n;}Node getTop(){    Node n = que.data[que.front];#ifdef QLOG    cout<<"getTop:"<<n.x<<","<<n.y<<",dir = "<<n.dir<<endl;#endif    return n;}void initQueue(){    que.front = que.rear = 0;}

到此基本上这个问题就说完了。





0 0
原创粉丝点击