0035算法笔记——【分支限界法】布线问题

介绍一种使用队列式分支限界法解决电路布线问题的算法。该算法通过广度优先搜索来寻找从起点到终点的最短路径,适用于印刷电路板上的布线问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

       问题描述

    印刷电路板将布线区域划分成n×m个方格如图a所示。精确的电路布线问题要求确定连接方格a的中点到方格b的中点的最短布线方案。在布线时,电路只能沿直线或直角布线,如图b所示。为了避免线路相交,已布了线的方格做了封锁标记,其它线路不允穿过被封锁的方格。 


    一个布线的例子:图中包含障碍。起始点为a,目标点为b。


     算法思想

      解此问题的队列式分支限界法从起始位置a开始将它作为第一个扩展结点。与该扩展结点相邻并且可达的方格成为可行结点被加入到活结点队列中,并且将这些方格标记为1,即从起始方格a到这些方格的距离为1。

     接着,算法从活结点队列中取出队首结点作为下一个扩展结点,并将与当前扩展结点相邻且未标记过的方格标记为2,并存入活结点队列。这个过程一直继续到算法搜索到目标方格b或活结点队列为空时为止。即加入剪枝的广度优先搜索。

     算法具体代码如下:

     1、Queue.h

  1. #include<iostream>   
  2. using namespace std;  
  3.   
  4. template <class T>  
  5. class Queue  
  6. {  
  7.     public:  
  8.         Queue(int MaxQueueSize=50);  
  9.         ~Queue(){delete [] queue;}  
  10.         bool IsEmpty()const{return front==rear;}  
  11.         bool IsFull(){return ( (  (rear+1)  %MaxSize==front )?1:0);}  
  12.         T Top() const;  
  13.         T Last() const;  
  14.         Queue<T>& Add(const T& x);  
  15.         Queue<T>& AddLeft(const T& x);  
  16.         Queue<T>& Delete(T &x);  
  17.         void Output(ostream& out)const;  
  18.         int Length(){return (rear-front);}  
  19.     private:  
  20.         int front;  
  21.         int rear;  
  22.         int MaxSize;  
  23.         T *queue;  
  24. };  
  25.   
  26. template<class T>  
  27. Queue<T>::Queue(int MaxQueueSize)  
  28. {  
  29.     MaxSize=MaxQueueSize+1;  
  30.     queue=new T[MaxSize];  
  31.     front=rear=0;  
  32. }  
  33.   
  34. template<class T >  
  35. T Queue<T>::Top()const  
  36. {  
  37.     if(IsEmpty())  
  38.     {  
  39.         cout<<"queue:no element,no!"<<endl;  
  40.         return 0;  
  41.     }  
  42.     else return queue[(front+1) % MaxSize];  
  43. }  
  44.   
  45. template<class T>  
  46. T Queue<T> ::Last()const  
  47. {  
  48.     if(IsEmpty())  
  49.     {  
  50.         cout<<"queue:no element"<<endl;  
  51.         return 0;  
  52.     }  
  53.     else return queue[rear];  
  54. }  
  55.   
  56. template<class T>  
  57. Queue<T>&  Queue<T>::Add(const T& x)  
  58. {  
  59.     if(IsFull())cout<<"queue:no memory"<<endl;  
  60.     else  
  61.     {  
  62.         rear=(rear+1)% MaxSize;  
  63.         queue[rear]=x;  
  64.     }  
  65.     return *this;  
  66. }  
  67.   
  68. template<class T>  
  69. Queue<T>&  Queue<T>::AddLeft(const T& x)  
  70. {  
  71.     if(IsFull())cout<<"queue:no memory"<<endl;  
  72.     else  
  73.     {  
  74.         front=(front+MaxSize-1)% MaxSize;  
  75.         queue[(front+1)% MaxSize]=x;  
  76.     }  
  77.     return *this;  
  78. }  
  79.   
  80. template<class T>  
  81. Queue<T>&  Queue<T> ::Delete(T & x)  
  82. {  
  83.     if(IsEmpty())cout<<"queue:no element(delete)"<<endl;  
  84.     else   
  85.     {  
  86.         front=(front+1) % MaxSize;  
  87.         x=queue[front];  
  88.     }  
  89.     return *this;  
  90. }  
  91.   
  92.   
  93. template<class T>  
  94. void Queue <T>::Output(ostream& out)const  
  95. {  
  96.     for(int i=rear%MaxSize;i>=(front+1)%MaxSize;i--)  
  97.        out<<queue[i];  
  98. }  
  99.   
  100. template<class T>  
  101. ostream& operator << (ostream& out,const Queue<T>& x)  
  102. {x.Output(out);return out;}  
#include<iostream>
using namespace std;

template <class T>
class Queue
{
	public:
		Queue(int MaxQueueSize=50);
		~Queue(){delete [] queue;}
		bool IsEmpty()const{return front==rear;}
		bool IsFull(){return ( (  (rear+1)  %MaxSize==front )?1:0);}
		T Top() const;
		T Last() const;
		Queue<T>& Add(const T& x);
		Queue<T>& AddLeft(const T& x);
		Queue<T>& Delete(T &x);
		void Output(ostream& out)const;
		int Length(){return (rear-front);}
	private:
		int front;
		int rear;
		int MaxSize;
		T *queue;
};

template<class T>
Queue<T>::Queue(int MaxQueueSize)
{
	MaxSize=MaxQueueSize+1;
	queue=new T[MaxSize];
	front=rear=0;
}

template<class T >
T Queue<T>::Top()const
{
	if(IsEmpty())
	{
		cout<<"queue:no element,no!"<<endl;
		return 0;
	}
	else return queue[(front+1) % MaxSize];
}

template<class T>
T Queue<T> ::Last()const
{
	if(IsEmpty())
	{
		cout<<"queue:no element"<<endl;
		return 0;
	}
	else return queue[rear];
}

template<class T>
Queue<T>&  Queue<T>::Add(const T& x)
{
	if(IsFull())cout<<"queue:no memory"<<endl;
	else
	{
		rear=(rear+1)% MaxSize;
	    queue[rear]=x;
	}
	return *this;
}

template<class T>
Queue<T>&  Queue<T>::AddLeft(const T& x)
{
	if(IsFull())cout<<"queue:no memory"<<endl;
	else
	{
		front=(front+MaxSize-1)% MaxSize;
		queue[(front+1)% MaxSize]=x;
	}
	return *this;
}

template<class T>
Queue<T>&  Queue<T> ::Delete(T & x)
{
	if(IsEmpty())cout<<"queue:no element(delete)"<<endl;
	else 
	{
		front=(front+1) % MaxSize;
		x=queue[front];
	}
	return *this;
}


template<class T>
void Queue <T>::Output(ostream& out)const
{
	for(int i=rear%MaxSize;i>=(front+1)%MaxSize;i--)
	   out<<queue[i];
}

template<class T>
ostream& operator << (ostream& out,const Queue<T>& x)
{x.Output(out);return out;}
     2、6d4.cpp

  1. //布线问题 队列式分支限界法求解    
  2. #include "stdafx.h"   
  3. #include "Queue.h"   
  4. #include <fstream>    
  5. #include <iostream>   
  6. using namespace std;  
  7.   
  8. ifstream fin("6d4.txt");   
  9.   
  10. const int n = 7;  
  11. const int m = 7;  
  12. int grid[n+2][m+2];    
  13.   
  14. struct Position    
  15. {    
  16.     int row;    
  17.     int col;    
  18. };   
  19.   
  20. bool FindPath(Position start,Position finish,int& PathLen,Position *&path);  
  21.   
  22. int main()  
  23. {  
  24.     int PathLen;  
  25.       
  26.     Position start,finish,*path;  
  27.   
  28.     start.row = 3;  
  29.     start.col = 2;  
  30.   
  31.     finish.row = 4;  
  32.     finish.col = 6;  
  33.   
  34.     cout<<"布线起点"<<endl;    
  35.     cout<<start.col<<" "<<start.row<<endl;    
  36.     cout<<"布线结束点"<<endl;    
  37.     cout<<finish.col<<" "<<finish.row<<endl;   
  38.   
  39.     cout<<"布线方格阵列如下(0表示允许布线,1表示不允许布线):"<<endl;  
  40.     for(int i=1; i<=m; i++)  
  41.     {  
  42.         for(int j=1; j<=n; j++)  
  43.         {  
  44.             fin>>grid[i][j];  
  45.             cout<<grid[i][j]<<" ";  
  46.         }  
  47.         cout<<endl;  
  48.     }  
  49.       
  50.     FindPath(start,finish,PathLen,path);  
  51.   
  52.     cout<<"布线长度为:"<<PathLen<<endl;  
  53.     cout<<"布线路径如下:"<<endl;    
  54.     for(int i=0; i<PathLen; i++)    
  55.     {    
  56.         cout<<path[i].col<<" "<<path[i].row<<endl;    
  57.     }    
  58.   
  59.     return 0;  
  60. }  
  61.   
  62. bool FindPath(Position start,Position finish,int& PathLen,Position *&path)  
  63. {  
  64.     //计算从起始位置start到目标位置finish的最短布线路径   
  65.     if((start.row == finish.row) && (start.col == finish.col))  
  66.     {  
  67.         PathLen = 0;  
  68.         return true;  
  69.     }  
  70.   
  71.     //设置方格阵列“围墙”   
  72.     for(int i=0; i<= m+1; i++)  
  73.     {  
  74.         grid[0][i]=grid[n+1][i]=1; //顶部和底部   
  75.     }  
  76.     for(int i=0; i<= n+1; i++)  
  77.     {  
  78.         grid[i][0]=grid[i][m+1]=1; //左翼和右翼   
  79.     }  
  80.   
  81.     //初始化相对位移   
  82.     Position offset[4];  
  83.   
  84.     offset[0].row=0;  
  85.     offset[0].col=1;//右   
  86.   
  87.     offset[1].row=1;   
  88.     offset[1].col=0;//下   
  89.   
  90.     offset[2].row=0;   
  91.     offset[2].col=-1;//左   
  92.       
  93.     offset[3].row=-1;  
  94.     offset[3].col=0;//上   
  95.       
  96.     int NumOfNbrs=4;//相邻方格数   
  97.     Position here,nbr;  
  98.     here.row=start.row;  
  99.     here.col=start.col;  
  100.   
  101.     grid[start.row][start.col]=2;//标记可达方格位置   
  102.     Queue<Position> Q;  
  103.   
  104.     do {//标记相邻可达方格   
  105.         for(int i=0; i<NumOfNbrs; i++)  
  106.         {  
  107.             nbr.row=here.row + offset[i].row;  
  108.             nbr.col=here.col+offset[i].col;  
  109.   
  110.             if(grid[nbr.row][nbr.col]==0)//该方格未被标记   
  111.             {  
  112.                 grid[nbr.row][nbr.col]=grid[here.row][here.col]+1;  
  113.                 if((nbr.row==finish.row) && (nbr.col==finish.col))  
  114.                 {  
  115.                     break//完成布线   
  116.                 }  
  117.                 Q.Add(nbr);  
  118.             }  
  119.         }  
  120.         //是否到达目标位置finish?   
  121.         if((nbr.row==finish.row) && (nbr.col==finish.col))  
  122.         {  
  123.             break;//完成布线   
  124.         }  
  125.   
  126.         //活结点队列是否非空?   
  127.         if(Q.IsEmpty())  
  128.         {  
  129.             return false;//无解   
  130.         }  
  131.         Q.Delete(here);//取下一个扩展结点   
  132.     }while(true);  
  133.   
  134.     //构造最短布线路径   
  135.     PathLen=grid[finish.row][finish.col]-2;  
  136.     path=new Position[PathLen];//从目标位置finish开始向起始位置回溯   
  137.     here=finish;  
  138.     for(int j=PathLen-1; j>=0; j--)  
  139.     {  
  140.         path[j]=here;//找前驱位置   
  141.         for(int i=0; i<NumOfNbrs; i++)  
  142.         {  
  143.             nbr.row=here.row+offset[i].row;  
  144.             nbr.col=here.col+offset[i].col;  
  145.             if(grid[nbr.row][nbr.col]==j+2)  
  146.             {  
  147.                 break;  
  148.             }  
  149.         }  
  150.         here=nbr;//向前移动   
  151.     }  
  152.     return true;  
  153. }  
//布线问题 队列式分支限界法求解 
#include "stdafx.h"
#include "Queue.h"
#include <fstream> 
#include <iostream>
using namespace std;

ifstream fin("6d4.txt"); 

const int n = 7;
const int m = 7;
int grid[n+2][m+2];  

struct Position  
{  
    int row;  
    int col;  
}; 

bool FindPath(Position start,Position finish,int& PathLen,Position *&path);

int main()
{
	int PathLen;
	
	Position start,finish,*path;

	start.row = 3;
	start.col = 2;

	finish.row = 4;
	finish.col = 6;

	cout<<"布线起点"<<endl;  
	cout<<start.col<<" "<<start.row<<endl;  
	cout<<"布线结束点"<<endl;  
    cout<<finish.col<<" "<<finish.row<<endl; 

	cout<<"布线方格阵列如下(0表示允许布线,1表示不允许布线):"<<endl;
	for(int i=1; i<=m; i++)
	{
		for(int j=1; j<=n; j++)
		{
			fin>>grid[i][j];
			cout<<grid[i][j]<<" ";
		}
		cout<<endl;
	}
	
	FindPath(start,finish,PathLen,path);

	cout<<"布线长度为:"<<PathLen<<endl;
	cout<<"布线路径如下:"<<endl;  
    for(int i=0; i<PathLen; i++)  
    {  
        cout<<path[i].col<<" "<<path[i].row<<endl;  
    }  

	return 0;
}

bool FindPath(Position start,Position finish,int& PathLen,Position *&path)
{
	//计算从起始位置start到目标位置finish的最短布线路径
	if((start.row == finish.row) && (start.col == finish.col))
	{
		PathLen = 0;
		return true;
	}

	//设置方格阵列“围墙”
	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; //左翼和右翼
	}

	//初始化相对位移
	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 NumOfNbrs=4;//相邻方格数
	Position here,nbr;
	here.row=start.row;
	here.col=start.col;

	grid[start.row][start.col]=2;//标记可达方格位置
	Queue<Position> Q;

	do {//标记相邻可达方格
		for(int i=0; i<NumOfNbrs; 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;
				if((nbr.row==finish.row) && (nbr.col==finish.col))
				{
					break; //完成布线
				}
				Q.Add(nbr);
			}
		}
		//是否到达目标位置finish?
		if((nbr.row==finish.row) && (nbr.col==finish.col))
		{
			break;//完成布线
		}

		//活结点队列是否非空?
		if(Q.IsEmpty())
		{
			return false;//无解
		}
		Q.Delete(here);//取下一个扩展结点
	}while(true);

	//构造最短布线路径
	PathLen=grid[finish.row][finish.col]-2;
	path=new Position[PathLen];//从目标位置finish开始向起始位置回溯
	here=finish;
	for(int j=PathLen-1; j>=0; j--)
	{
		path[j]=here;//找前驱位置
		for(int i=0; i<NumOfNbrs; 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;//向前移动
	}
	return true;
}
      程序运行结果如图:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值