1.问题描述:
把布线的区域画成一个网格,该网格用一个二维数组来存储,其中通路用0值表示,墙壁用1值表示,从该区域内的某一点向另一点布线,求布线的最短路径与路径长度。
2.解决办法:
把起点的值设置为2(与0和1区分开),然后把它四周走的通的点赋值为3,然后把值为3的点的四周走得通的点赋值为4,依次类推,直到走不下去或者赋值到终点,然后从终点按照数值依次减小的路线往回走即可找到最短路径。实现该操作需要队列这种数据结构,因为它有先进先出的功能。
3.实现代码:
# include"LinkedQueue.h"
# include<iostream>
const int m=7;
bool FindPath(offsets& start,offsets& finish,int& pathLen,offsets *&path,offsets move[4],int grid[][m+2]);
using namespace std;
void main(){
int pathLen; //路径长度
offsets* path; //路径数组指针
offsets move[4]={{-1,0},{0,1},{1,0},{0,-1}}; //移动数组:向四个方向移动
int grid[m+2][m+2]; //电路网格数组:值为0,可布线;值为1,不可布线需绕行
for(int i=0;i<=m+1;i++){ //把网格的四周元素都置为1,表示墙不可通过;
grid[0][i]=grid[m+1][i]=1;
grid[i][0]=grid[i][m+1]=1;
}
for(int i=1;i<=m;i++) //赋值1与0:设置障碍与通路
for(int j=1;j<=m;j++)
cin>>grid[i][j];
offsets start={3,2}; //起点与终点
offsets finish={4,6};
if(FindPath(start,finish,pathLen,path,move,grid)){ //调用找路函数:起点,终点,移动数组,与电路网格作为参数传递;路径与路径长度作为参数实现返回
cout<<pathLen<<endl;
for(int i=0;i<=pathLen-1;i++)
cout<<path[i]<<" "<<endl;
}
system("pause");
}
bool FindPath(offsets& start,offsets& finish,int& pathLen,offsets*& path,offsets move[4],int grid[][m+2]){ //找路函数
if(start.col==finish.col&&start.cow==finish.cow) { //起点恰好等于终点
pathLen=0;
return true;
}
offsets here,nbr; //here为此刻所处的位置,nbr为与here相邻的位置
here.col=start.col; //一开始处在起点
here.cow=start.cow;
grid[here.cow][here.col]=2; //赋值为2是为了与1和0分别开
LinkedQueue Q;
do{
for(int i=0;i<4;i++){ //往四个方向试探 先进先出,保证赋完所有3后在赋4,可保证找到的是最短路径
nbr.cow=here.cow+move[i].cow;
nbr.col=here.col+move[i].col;
if(grid[nbr.cow][nbr.col]==0){ //走得通
grid[nbr.cow][nbr.col]=grid[here.cow][here.col]+1; //把此刻点的值+1赋给相邻点
if(nbr.cow==finish.cow&&nbr.col==finish.col) break; //如果该点为终点 退出循环
Q.EnQueue(nbr); //相邻点的位置进队
}
}
if(nbr.cow==finish.cow&&nbr.col==finish.col) break;//内循环中找到终点,跳到此处,退出外循环
if(Q.isEmpty()) //表示此刻所处的点被封锁,无路可走
return false;
Q.DeQueue(here); //栈顶元素退栈,并赋值给here,继续往下走
}while(1);
pathLen=grid[nbr.cow][nbr.col]-2; //因为起点为2,路径长度为终点值-2
path=new offsets[pathLen]; //分配pathLen长度的储存空间来储存路径
if(path==NULL){
cerr<<"存储分配错误"<<endl;
exit(1);
}
here.cow=finish.cow; //从终点回溯
here.col=finish.col;
for(int i=pathLen-1;i>=0;i--){ //存走过的路径
path[i].cow=here.cow;
path[i].col=here.col;
for(int j=0;j<4;j++){
nbr.col=here.col+move[j].col;
nbr.cow=here.cow+move[j].cow;
if(grid[nbr.cow][nbr.col]==i+2) //该点是来时的点
break;
}
here.cow=nbr.cow; //从来时的点继续往回走
here.col=nbr.col;
}
return true;
}
链式队列:
struct LinkNode{ //自定义数据类型:结点
offsets date;
LinkNode* link;
LinkNode(LinkNode* ptr=NULL):link(ptr){}
LinkNode(const offsets x,LinkNode* ptr=NULL):date(x),link(ptr){}
};
class LinkedQueue{ //链式队列
private:
LinkNode* front; //队头指针
LinkNode* rear; //队尾指针
public:
LinkedQueue():front(NULL),rear(NULL){} //构造函数:构造空队列
void makeEmpty(); //将表置空
~LinkedQueue(){ makeEmpty();} //析构函数:(*不能直接用delete清空全部存储空间的析构函数往往需要调用另一个函数帮助清空)
bool EnQueue(offsets& x); //进队函数
bool DeQueue(offsets& x); //出队函数
bool getFront(offsets& x); //取队头
bool isEmpty(){ return (front==NULL)?true:false;} //判断表空
int getSize(); //求队列元素个数
friend ostream& operator<<(ostream& ostr,LinkedQueue& Q); //输出运算符重载
friend ostream& operator<<(ostream& ostr,offsets& x);
};
实现细节:
# include<iostream>
# include"LinkedQueue.h"
using namespace std;
void LinkedQueue::makeEmpty(){
LinkNode* ptr;
while(isEmpty()==false){
ptr=front;
front=front->link;
delete ptr;
rear=NULL; //删除尾结点后尾指针需要置空
}
}
bool LinkedQueue::EnQueue(offsets& x){
if(isEmpty()){
front=rear=new LinkNode(x);
if(front==NULL) return false;
}
else{
rear->link=new LinkNode(x);
if(rear->link==NULL) return false;
rear=rear->link;
}
return true;
}
bool LinkedQueue::DeQueue(offsets& x){
if(isEmpty()) return false;
else{
x=front->date;
LinkNode* current=front;
front=front->link;
delete current;
}
return true;
}
bool LinkedQueue::getFront(offsets& x){
if(isEmpty()) return false;
else{
x=front->date;
return true;
}
}
int LinkedQueue::getSize(){
int count=0;
LinkNode* ptr=front;
while(ptr!=NULL){
count++;
ptr=ptr->link;
}
return count;
}
ostream& operator<<(ostream& ostr,offsets& x){
ostr<<x.cow<<" "<<x.col<<endl;
return ostr;
}
ostream& operator<<(ostream& ostr,LinkedQueue& Q){
LinkNode* current=Q.front;int i=0;
while(current!=NULL){
ostr<<++i<<":"<<current->date<<endl;
current=current->link;
}
return ostr;
}