布线问题(分支限界)

问题描述:

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

电路板布线问题,对给定的电路板,找出最短的布线路径。

 

算法思路:

       布线问题的解空间是一个排列树。采用队列式分支限界从起始位置start开始,将其作为第一个可扩展的结点。与该扩展结点相邻(即上下左右四个方向)且可达的方格成为可行结点被加入到活结点队列中,并且将这些方格标记为1,即从起始位置start到这些方格的距离为1。然后从活结点队列取出队首结点作为下一个可扩展的结点,并将与当前扩展结点相邻且未被标记过的方格标记为2,并存入活结点队列。继续执行该算法直到搜索到终止结点finish或者队列为空为止。

    对于方格阵列的建立:用0表示可达且未被标记过的结点,用1表示该方格不可达。为了防止出界,可以在方格阵列外围用1建立不可达的“围墙”。由于0和1被使用过,起始位置可以从2开始,等价于将距离起始位置的标记距离都做了加2处理,那么实际距离为标记距离减2。

 

代码附录:

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0

typedef int Status;

//队列的最大长度 
#define MAXQSIZE 20

struct Position{
	int row;			// 行 
	int col;			// 列 
};
typedef Position QElemType;
// 循环队列
typedef struct{
	QElemType *base;
	int front;
	int rear;
}SqQueue;

//实现队列的一般功能
Status InitQueue(SqQueue &Q){
	Q.base = (QElemType*)malloc(MAXQSIZE*sizeof(QElemType));
	if(!Q.base) exit(OVERFLOW);
	Q.front=Q.rear=0;
	return OK;
}

Status QueueEmpty(SqQueue Q){
	return Q.rear==Q.front;
}

Status EnQueue(SqQueue &Q,QElemType e){
	if((Q.rear+1)%MAXQSIZE==Q.front) return ERROR;
	Q.base[Q.rear] = e;
	Q.rear = (Q.rear+1) % MAXQSIZE;
	return OK;
}

Status DeQueue(SqQueue &Q,QElemType &e){
	if(Q.rear==Q.front) return ERROR;
	e=Q.base[Q.front];
	Q.front=(Q.front+1)%MAXQSIZE;
	return OK;
}

int n,			// n行 
	m;			// m列 
int **grid;		// 区域阵列 

Status FindPath(Position start, Position finish, int &PathLen, Position *&Path){
	if(start.col == finish.col && start.row == finish.row) {
		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.col = start.col; here.row = start.row;
	grid[start.row][start.col] = 2;
	// 初始化队列 
	SqQueue Q; InitQueue(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;
				EnQueue(Q,nbr);
			}
		}
		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;
	Path = new Position[PathLen];
	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;
} 

测试用例:

运行结果:

补充:

int main(){
    int pathLength;
    Position start = {3,2};        // 起点
    Position finish = {4,6};       // 终点
    Position* path;
    FILE *file = fopen("test.txt","r");
    fscanf(file,"%d",&n); 
    fscanf(file,"%d",&m); 
    grid = new int *[n+2];
    for(int i = 1; i < n+2; i++){
    	grid[i] = new int [n+2];
    }
    for(int i = 1;i<=n;i++){
    	for(int j = 1; j<=n; j++) fscanf(file,"%d",&grid[i][j]);
    }
    fclose(file);
    FindPath(start,finish,pathLength,path);
    printf("从起始位置到结束位置经历的最少方格数:%d\n",pathLength);
    printf("从起始位置到结束位置经历的方格:");
    for(int i = 0; i < pathLength; i++){
    	printf("(%d,%d) ",path[i].row,path[i].col);
    }
    delete grid;
    return 0;
}

test.txt:

7
7
0 0 1 0 0 0 0
0 0 1 1 0 0 0
0 0 0 0 1 0 0
0 0 0 1 1 0 0
1 0 0 0 1 0 0
1 1 1 0 0 0 0
1 1 1 0 0 0 0

 

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值