计算机算法设计与分析(第5版)王晓东著 p178
0:电路板中可行的方格 1:障碍物 2:起点
是按课本上来的,初始起点设为2 是为了和 0,1进行区分
起点:1,1
终点: 4,6
1.path[] 数组是存放的起点到终点的路径方格
2.电路板最外面的一层全部赋值为1,表示围墙
3.数据结构是用的循环队列,循环队列中的最后一个位置是不存放值的,我这里的MAX是设的足够大,先进先出(FIFO)的方式满足队列式分支限界法
实现结果:
C代码:
//穷举+回溯
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<malloc.h>
#define n 5 //方格行
#define m 6
typedef struct{ //方格
int row; //行
int col;
}Position;
#define MAX 100 //循环队列大小
typedef struct{
Position *base;
int front,rear;
}CqQueue;
//初始化队列
void InitQueue(CqQueue &Q)
{
Q.base=(Position*)malloc(MAX*sizeof(Position));
if(!Q.base)
exit(0);
Q.front=Q.rear=0;
}
//判断队列是否为空
bool QueueEmpty(CqQueue Q)
{
if(Q.front==Q.rear)
return true; ///exit用于退出程序,return退出当前的函数
return false;
}
//尾插队列
int EnQueue(CqQueue &Q,Position e)
{
if((Q.rear+1)%MAX==Q.front)
//牺牲了一个存储空间,此时数据存储到4位置,Q.rear此时等于5,即5位置没有数据
return 1;
Q.base[Q.rear]=e;
Q.rear=(Q.rear+1)%MAX;
}
//出队列
void DeQueue(CqQueue &Q,Position &e)
{
if(Q.rear==Q.front)
exit(0); // 队列为空
e=Q.base[Q.front];
Q.front=(Q.front+1)%MAX;
}
//计算从起始位置start到目标位置finish的最短布线路径
bool FindPath(Position &start,Position &finish,int PathLen,Position *path,CqQueue &Q){
int grid[n+2][m+2];
//初始化
for(int i=0;i<n+2;i++){
for(int j=0;j<m+2;j++){
grid[i][j]=0;
}
}
//障碍:
// grid[3][6]=1;
// grid[4][5]=1;
//设置方格阵列 “围墙 ”
for(int i=0;i<=m+1;i++){
grid[0][i] = grid[n+1][i]=1; //顶部和底部
}
for(int i=0;i<=n+1;i++){
grid[i][0] = grid[i][m+1] =1; //左边和右边
}
//设初始点(1,1)和终点(4,6)
start.row = 1; start.col = 1;
finish.row = 4; finish.col = 6;
//找到最短布线路径则返回true,否则返回false
if((start.row == finish.row)&&(start.col == finish.col)){
PathLen = 0;
return true;
}
//初始化相对位移
Position offset[4];
offset[0].row=0; offset[0].col=1; //右
offset[1].row=1; offset[1].col=0; //下
offset[2].row=0; offset[2].col=-1; //左
offset[3].row=-1; offset[3].col=0; //上
int Numbrs = 4; //相邻方格数
Position here,nbr;
here.row = start.row; //目前的点为出发点的坐标
here.col = start.col;
grid[start.row][start.col] = 2;
// LinkedQueue<Position> Q; //标记可达方格位置 改为队列
do{
for(int i=0;i<Numbrs;i++){
nbr.row = here.row+offset[i].row;
nbr.col = here.col+offset[i].col;
if(grid[nbr.row][nbr.col]==0){
//该方格未标记
grid[nbr.row][nbr.col] = grid[here.row][here.col]+1; //当前方格的值+1
if((nbr.row==finish.row)&&(nbr.col==finish.col))
break; //完成布线
EnQueue(Q,nbr); //把可行的方格加入队列,按右下左上的顺序依次加入
}
}
//是否到达目标位置finish
if((nbr.row ==finish.row)&&(nbr.col==finish.col))
break;
//活结点队列是否非空
if(QueueEmpty(Q))
return false; //无解
DeQueue(Q,here); //取下一个扩展结点
}while(true);
//构造最短布线路径
PathLen = grid[finish.row][finish.col]-2; //等于终点的值-2
printf("路径长度:%d\n",PathLen);
path = new Position[PathLen]; //结构体数组?
//从目标位置finish开始向起始位置回溯
here = finish;
for(int j=PathLen-1;j>=0;j--){
path[j]=here;
//找前驱位置
for(int i=0;i<Numbrs;i++){
nbr.row = here.row+offset[i].row;
nbr.col = here.col+offset[i].col;
if(grid[nbr.row][nbr.col]==j+2)
break;
}
here = nbr; //向前移动
}
printf("寻路路径如下:\n(%d,%d)\n",here.row,here.col); //起点
for(int i=0;i<=PathLen-1;i++){
printf("(%d,%d)\n",path[i].row,path[i].col);
}
printf("方格如下:\n");
for(int i=0;i<n+2;i++){
for(int j=0;j<m+2;j++){
printf("%d ",grid[i][j]);
}
printf("\n");
}
return true;
}
int main(){
//队列
CqQueue Q;
InitQueue(Q); //初始化
//方格
Position start; //起点
Position finish; //终点
int pathlen; //路径长度
Position *path; //存放路径
FindPath(start,finish,pathlen,path,Q);
return 0;
}