電路布線問題--分支限界法求解
一 問題描述:
布線問題:印刷電路板將布線區域划分成n×m個方格陣列,要求確定連接方格陣列中的方格a的中點到方格b的中點的最短布線方案。在布線時,電路只能沿直線或直角布線,為了避免線路相交,已布了線的方格做了封鎖標記,其他線路不允許穿過被封鎖的方格。
二 算法應用:
用分支限界法解此布線問題。分支限界法類似回溯法,也是一種在問題的解空間樹T上搜索問題解的算法。但分支限界法只找出滿足約束條件的一個最優解,並且以廣度優先或最小耗費優先的方式搜索解空間樹T。樹T是一棵子集樹或排列樹。在搜索時,每個結點只有一次機會成為擴展結點,並且一次性產生其所有兒子結點。從活結點表中選擇下一擴展結點有兩種方式:(1)隊列式(FIFO) (2)優先隊列式。分支限界法廣泛應用於單源最短路徑問題,最大團問題,布線問題,電路板排列問題等。
三 求解思路:
用隊列式分支限界法來考慮布線問題。布線問題的解空間是一個圖,則從起始位置a開始將它作為第一個擴展結點。與該擴展結點相鄰並可達的方格成為可行結點被加入到活結點隊列中,並且將這些方格標記為1,即從起始方格a到這些方格的距離為1。接着,從活結點隊列中取出隊首結點作為下一個擴展結點,並將與當前擴展結點相鄰且未標記過的方格標記為2,並存入活結點隊列。這個過程一直繼續到算法搜索到目標方格b或活結點隊列為空時為止。
四 算法思路:
在實現上述算法時,
(1) 定義一個表示電路板上方格位置的類Position。
它的2個成員row和col分別表示方格所在的行和列。在方格處,布線可沿右、下、左、上4個方向進行。沿這4個方向的移動分別記為0,1,2,3。下表中,offset[i].row和offset[i].col(i= 0,1,2,3)分別給出沿這4個方向前進1步相對於當前方格的相對位移。
| 移動i |
方向 |
offset[i].row |
offset[i].col |
| 0 1 2 3 |
右 下 左 上 |
0 1 0 -1 |
1 0 -1 0 |
(2) 用二維數組grid表示所給的方格陣列。
初始時,grid[i][j]= 0, 表示該方格允許布線,而grid[i][j]= 1表示該方格被封鎖,不允許布線。
五 舉例說明:
一個7×7方格陣列布線如下:
起始位置是a =(3,2),目標位置是b =(4,6),陰影方格表示被封鎖的方格。當算法搜索到目標方格b時,將目標方格b標記為從起始位置a到b的最短距離。此例中, a到b的最短距離是9。

代碼轉自http://blog.csdn.net/ei__nino/article/details/8195906
#include <iostream>
#include <queue>
using namespace std;
int m=8;
int n=8;
int grid[10][10];
int indexcount=0;
struct Position
{
int row;
int col;
};
void showPath()
{
for(int i=0; i<10; i++)
{
for(int j=0; j<10; j++)
cout<<grid[i][j]<<" ";
cout<<endl;
}
cout<<"------------------"<<endl;
}
bool FindPath(Position start,Position finish,int &PathLen,Position *&path)
{
//計算從起點位置start到目標位置finish的最短布線路徑,找到最短布線路//徑則返回true,否則返回false
if((start.row==finish.row) && (start.col==finish.col))
{
PathLen=0;
cout<<"start=finish"<<endl;
return true;
} //start=finish
//設置方格陣列“圍牆”
//初始化圖,-1為未訪問
for(int i=1; i<9; i++)
{
for(int j=1; j<9; j++)
grid[i][j]=-1;
}
//添加阻擋點
grid[2][3]=-2;
for(int i=0; i<= m+1; i++)
grid[0][i]=grid[n+1][i]=-2; //頂部和底部
for(int i=0; i<= n+1; i++)
grid[i][0]=grid[i][m+1]=-2; //左翼和右翼
//初始化相對位移
cout<<"完整圖"<<endl;
showPath();
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]=0;
//標記可達方格位置
cout<<"布線前圖"<<endl;
showPath();
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]==-1)
{
//該方格未被標記
//cout<<grid[nbr.row][nbr.col]<<endl;//顯示路標值
grid[nbr.row][nbr.col]=grid[here.row][here.col]+1;
//cout<<nbr.col<<" "<<nbr.row<<endl;//顯示坐標
}
if((nbr.row==finish.row) &&(nbr.col==finish.col)) break; //完成布線
Q.push(nbr);
}
//是否到達目標位置finish?
if((nbr.row==finish.row)&&(nbr.col==finish.col)) break;//完成布線
//活結點隊列是否非空?
if(Q.empty()) return false;//無解
here = Q.front();
//cout<<here.col<<" "<<here.row<<endl;
Q.pop();//取下一個擴展結點
indexcount++;
// cout<<"下一節點"<<indexcount<<endl;
}
while(true);
//構造最短布線路徑
PathLen=grid[finish.row][finish.col];
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)
{
// cout<<j<<endl;
break;
}
}
here=nbr;//向前移動
}
return PathLen;
}
int main()
{
Position start;
start.col=1;
start.row=1;
cout<<"布線起點"<<endl;
cout<<start.col<<" "<<start.row<<endl;
Position finish;
finish.row=3;
finish.col=4;
cout<<"布線結束點"<<endl;
cout<<finish.col<<" "<<finish.row<<endl;
int PathLen=0;
Position *path;
FindPath(start,finish,PathLen,path);
cout<<"布線后路徑圖"<<endl;
showPath();
cout<<"路徑"<<endl;
for(int i=0; i<PathLen; i++)
{
cout<<path[i].col<<" "<<path[i].row<<endl;
}
cout << "布線問題完畢!" << endl;
system("pause");
return 0;
}
