雷火电竞-中国电竞赛事及体育赛事平台

歡迎來到入門教程網(wǎng)!

C語言

當前位置:主頁 > 軟件編程 > C語言 >

算法詳解之分支限界法的具體實現(xiàn)

來源:本站原創(chuàng)|時間:2020-01-10|欄目:C語言|點擊:

首先我們來關注一個問題:

問題描述:

布線問題:印刷電路板將布線區(qū)域劃分成n×m個方格陣列,要求確定連接方格陣列中的方格a的中點到方格b的中點的最短布線方案。在布線時,電路只能沿直線或直角布線,為了避免線路相交,已布了線的方格做了封鎖標記,其他線路不允許穿過被封鎖的方格。如下圖所示:

 

算法思路:

布線問題的解空間是一個圖,則從起始位置a開始將它作為第一個擴展結(jié)點。與該擴展結(jié)點相鄰并可達的方格成為可行結(jié)點被加入到活結(jié)點隊列中,并且將這些方格標記為1,即從起始方格a到這些方格的距離為1。接著,從活結(jié)點隊列中取出隊首結(jié)點作為下一個擴展結(jié)點,并將與當前擴展結(jié)點相鄰且未標記過的方格標記為2,并存入活結(jié)點隊列。這個過程一直繼續(xù)到算法搜索到目標方格b或活結(jié)點隊列為空時為止。

在實現(xiàn)上述算法時,

(1) 定義一個表示電路板上方格位置的類Position。

它的2個成員row和col分別表示方格所在的行和列。在方格處,布線可沿右、下、左、上4個方向進行。沿這4個方向的移動分別記為0,1,2,3。下表中,offset[i].row和offset[i].col(i= 0,1,2,3)分別給出沿這4個方向前進1步相對于當前方格的相對位移。

(2) 用二維數(shù)組grid表示所給的方格陣列。

初始時,grid[i][j] = 0, 表示該方格允許布線,而grid[i][j] = 1表示該方格被封鎖,不允許布線。

算法圖解:

代碼貼出來:

復制代碼 代碼如下:

#include <stdio.h>
typedef struct {
  int row;
  int col;
}Position;
int FindPath (Position start, Position finish, int &PathLen, Position *&path)
{ //計算從起始位置start到目標位置finish的最短布線路徑,找到返回1,否則,返回0
  int  i;
  if ((start.row = = finish.row) && (start.col = = finish.col)) {
PathLen = 0;   return 0; } //start = finish
  //設置方格陣列”圍墻”
  for (i = 0; i <= m+1; i++)
grid[0][i] = grid[n+1][i] = 1; //頂部和底部
  for (i = 0; i <= n+1; i++)
grid[i][0] = grid[i][m+1] = 1; //左翼和右翼
  //初始化相對位移
int  NumOfNbrs = 4; //相鄰方格數(shù)
  Position offset[4], here, nbr;
  offset[0].row = 0;   offset[0].col = 1;   //右
  offset[0].row = 1;   offset[0].col = 0;   //下
  offset[0].row = 0;   offset[0].col = -1;  //左
  offset[0].row = -1;  offset[0].row = 0;  //上
  here.row = start.row;
  here.col = start.col;
  LinkedQueue <Position> Q; //標記可達方格位置
  do {
for (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); 
       }
}
if ((nbr.row = = finishi.row) && (nbr.col = = finish.col))  break;//完成布線
if (Q.IsEmpty()) //活隊列是否為空
return 0; //無解
      Q.delete(here); //取下一個擴展結(jié)點
}while (1);
//構(gòu)造最短布線路徑
PathLen = grid[finish.row][finish.col] - 2;
path = new Position[PathLen];
here = finish;
for (int j = PathLen – 1; j >= 0; j--) { //找前驅(qū)位置
  path[j] = here;
  for (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 1;
}
void main ()
{
  int grid[8][8];
  int PathLen, *path;
  Position start, finish;
  start.row = 3;  start.col = 2;
  finish.row = 4; finish.col = 6;


  FindPath (start, finish, PathLen, path);
 }

代碼貼出來:

復制代碼 代碼如下:

#include <stdio.h>
typedef struct {
  int row;
  int col;
}Position;
int FindPath (Position start, Position finish, int &PathLen, Position *&path)
{ //計算從起始位置start到目標位置finish的最短布線路徑,找到返回1,否則,返回0
  int  i;
  if ((start.row = = finish.row) && (start.col = = finish.col)) {
PathLen = 0;   return 0; } //start = finish
  //設置方格陣列”圍墻”
  for (i = 0; i <= m+1; i++)
grid[0][i] = grid[n+1][i] = 1; //頂部和底部
  for (i = 0; i <= n+1; i++)
grid[i][0] = grid[i][m+1] = 1; //左翼和右翼
  //初始化相對位移
int  NumOfNbrs = 4; //相鄰方格數(shù)
  Position offset[4], here, nbr;
  offset[0].row = 0;   offset[0].col = 1;   //右
  offset[0].row = 1;   offset[0].col = 0;   //下
  offset[0].row = 0;   offset[0].col = -1;  //左
  offset[0].row = -1;  offset[0].row = 0;  //上
  here.row = start.row;
  here.col = start.col;
  LinkedQueue <Position> Q; //標記可達方格位置
  do {
for (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); 
       }
}
if ((nbr.row = = finishi.row) && (nbr.col = = finish.col))  break;//完成布線
if (Q.IsEmpty()) //活隊列是否為空
return 0; //無解
      Q.delete(here); //取下一個擴展結(jié)點
}while (1);
//構(gòu)造最短布線路徑
PathLen = grid[finish.row][finish.col] - 2;
path = new Position[PathLen];
here = finish;
for (int j = PathLen – 1; j >= 0; j--) { //找前驅(qū)位置
  path[j] = here;
  for (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 1;
}
void main ()
{
  int grid[8][8];
  int PathLen, *path;
  Position start, finish;
  start.row = 3;  start.col = 2;
  finish.row = 4; finish.col = 6;


  FindPath (start, finish, PathLen, path);
 }


好了,問題解出來了。咦,我們用的是什么方法呢?呵呵,對,這就是分支限界算法。


算法總結(jié):

分支限界法基本思想:

• 分支限界法常以廣度優(yōu)先或以最小耗費(最大效益)優(yōu)先的方式搜索問題的解空間樹。

• 在分支限界法中,每一個活結(jié)點只有一次機會成為擴展結(jié)點?;罱Y(jié)點一旦成為擴展結(jié)點,就一次性產(chǎn)生其所有兒子結(jié)點。

• 在這些兒子結(jié)點中,導致不可行解或?qū)е路亲顑?yōu)解的兒子結(jié)點被舍棄,其余兒子結(jié)點被加入活結(jié)點表中。

• 此后,從活結(jié)點表中取下一結(jié)點成為當前擴展結(jié)點,并重復上述結(jié)點擴展過程。這個過程一直持續(xù)到找到所需的解或活結(jié)點表為空時為止。

分支限界法與回溯法的不同:

(1)求解目標不同:回溯法的求解目標是找出解空間樹中滿足約束條件的所有解,而分支限界法的求解目標則是找出滿足約束條件的一個解,或是在滿足約束條件的解中找出在某種意義下的最優(yōu)解。

(2)搜索方式的不同:回溯法以深度優(yōu)先的方式搜索解空間樹,而分支限界法則以廣度優(yōu)先或以最小耗費優(yōu)先的方式搜索解空間樹。

上一篇:C++中的幾種排序算法

欄    目:C語言

下一篇:枚舉窗口句柄后關閉所有窗口示例

本文標題:算法詳解之分支限界法的具體實現(xiàn)

本文地址:http://www.jygsgssxh.com/a1/Cyuyan/3777.html

網(wǎng)頁制作CMS教程網(wǎng)絡編程軟件編程腳本語言數(shù)據(jù)庫服務器

如果侵犯了您的權(quán)利,請與我們聯(lián)系,我們將在24小時內(nèi)進行處理、任何非本站因素導致的法律后果,本站均不負任何責任。

聯(lián)系QQ:835971066 | 郵箱:835971066#qq.com(#換成@)

Copyright © 2002-2020 腳本教程網(wǎng) 版權(quán)所有