实验原理
1. 基本思想
分支是使用广度优先策略,依次生成扩展结点的所有分支。
限界是在结点扩展过程中,计算结点的上界,搜索的同时剪掉某些分支。
分支限界法就是把问题的可行解展开,再由各个分支寻找最佳解。
与回溯法类似,分支限界法也是在解空间中搜索得到解;
不同的是,分支限界法会生成所有扩展结点,并舍弃不可能通向最优解的结点,然后根据广度优先/最小耗费优先,从活结点中选择一个作为扩展结点,使搜索向解空间上有最优解的分支推进。
2. 搜索策略
分支限界法首先生成当前扩展结点的所有分支,然后再从所有活结点中选择一个作为扩展结点。每一个活结点都要计算限界,根据限界情况判断是否剪枝,或选择最有利的结点。
|
源程序:
方法一:
//单源最短路径
class Graph{ //带权有向图
private:
int n; //顶点个数
int **c; //邻接矩阵
int *dist; //记录路径
public:
void shortestPaths(int);
Graph(); //根据情况构造图
};
class MinHeapNode{ //最小堆的结点
friend Graph;
private:
int i; //结点对应的顶点编号
int length; //结点记录的最短路径
public:
int getI(){ return i; }
void setI(int i){ this->i = i; }
int getLength(){ return length; }
void setLength(int length){ this->length = length; }
};
class MinHeap{ //最小堆(虽然叫堆,但其实并不是用堆实现的)
friend Graph;
private:
int length; //最小堆的长度,等同于顶点个数
MinHeapNode *nodes; //结点数组
public:
MinHeap(int n)
{
this->length = n;
nodes = new MinHeapNode[n];
}
void deleteMin(MinHeapNode&); //令当前节点出队列,并给出下一个扩展结点
void insertNode(MinHeapNode N) //结点入队列,将原结点的内容替换即可
{
nodes[N.getI()].setI(N.getI());
nodes[N.getI()].setLength(N.getLength());
}
bool outOfBounds() //检查队列为空
{
for(int i = 0;i < length;i++)
if(nodes[i].getI() != -1)
return false;
return true;
}
};
void MinHeap::deleteMin(MinHeapNode &E)
{
int j = E.getI();
nodes[j].setI(-1);
nodes[j].setLength(-1); //标记为出队列
int tmp = INT_MAX;
for(int i = 0;i < length;i++){ //给出路径最短的结点作为扩展结点
if(nodes[i].getI() != -1 && nodes[i].getLength() < tmp){
E.setI(i);
E.setLength(nodes[i].getLength());
tmp = nodes[i].getLength();
}
}
}
void Graph::shortestPaths(int start)
{
MinHeap heap = MinHeap(n);
MinHeapNode E = MinHeapNode(); //别问,一开始还加了new,太久不写C++了
E.i = start;
E.length = 0;
dist[start] = 0; //初始为源点V,对应编号start
while(true){
for(int j = 0;j < n;j++){ //检查所有邻接顶点
if(c[E.i][j] != 0){ //是否邻接
if(E.length + c[E.i][j] < dist[j]){ //是否满足限界,当前路径小于记录的最短路径
dist[j] = E.length + c[E.i][j]; //更新
if(/*填入判断表达式*/){ //没有邻接顶点的点不入队,按情况调整,没有也可以,但会造成无效开销
MinHeapNode N = MinHeapNode(); //创建一个新的结点,并令其入队列
N.i = j;
N.length = dist[j];
heap.insertNode(N);
}
}
}
}
if(heap.outOfBounds()) //队列为空,结束
break;
heap.deleteMin(E); //该结点已经生成全部分支,出队列并取得下一扩展结点
}
}
方法二:
#include <iostream>
#include<queue>
using namespace std;
typedef struct ArcCell{
int adj;//保存权值
int info;//存储最短路径长度
}ArcCell,AdjMaxtrix[100][100];
typedef struct{
int data;
int length;
}VerType;
typedef struct{
VerType vexs[100];//顶点向量
AdjMaxtrix arcs;
int vexnum;//顶点数
int arcnum;//弧数
}Graph;
Graph G;
queue<int> q;
void CreateGraph()
{
int m,n,t;
printf("输入顶点数和弧数:");
scanf("%d%d",&G.vexnum,&G.arcnum);
printf("输入顶点:");
for(int i=1;i<=G.vexnum;i++)
{
scanf("%d",&G.vexs[i].data);
G.vexs[i].length=10000;
}
for(int i=1;i<=G.vexnum;i++)
for(int j=1;j<=G.vexnum;j++)
{
G.arcs[i][j].adj=0;
}
printf("输入弧及权重:\n");
for(int i=1;i<=G.arcnum;i++)
{
scanf("%d%d%d",&m,&n,&t);
G.arcs[m][n].adj=1;
G.arcs[m][n].info=t;
}
}
int NextAdj(int v,int w)
{
for(int i=w+1;i<=G.vexnum;i++)
if(G.arcs[v][i].adj)
return i;
return 0;//not found;
}
void ShortestPaths(int v)
{
int k=0;//从首个节点开始访问
int t;
G.vexs[v].length=0;
q.push(G.vexs[v].data);
while(!q.empty())
{
t=q.front();
k=NextAdj(t,k);
while(k!=0)
{
if(G.vexs[t].length+G.arcs[t][k].info<=G.vexs[k].length)//减枝操作
{
G.vexs[k].length=G.vexs[t].length+G.arcs[t][k].info;
q.push(G.vexs[k].data);
}
k=NextAdj(t,k);
}
q.pop();
}
}
void Print()
{
for(int i=1;i<=G.vexnum;i++)
printf("%d------%d\n",G.vexs[i].data,G.vexs[i].length);
}
int main()
{
CreateGraph();
ShortestPaths(1);
Print();
return 0;
}
方法三:
#include <iostream>
#include<vector>
#include<queue>
using namespace std;
typedef struct ArcCell{
int u;//保存权值
int info;//存储最短路径长度
ArcCell(int a,int b):u(a),info(b){
}
}ArcCell,AdjMaxtrix[100][100];
typedef struct{
int data;
int length;
}VerType;
typedef struct{
VerType vexs[100];//顶点向量
vector<ArcCell>arcs[1001];
int vexnum;//顶点数
int arcnum;//弧数
}Graph;
Graph G;
queue<int> q;
void CreateGraph()
{
int m,n,t;
printf("输入顶点数和弧数:");
scanf("%d%d",&G.vexnum,&G.arcnum);
printf("输入顶点:");
for(int i=1;i<=G.vexnum;i++)
{
scanf("%d",&G.vexs[i].data);
G.vexs[i].length=10000;
}
printf("输入弧及权重:\n");
for(int i=1;i<=G.arcnum;i++)
{
scanf("%d%d%d",&m,&n,&t);
G.arcs[m].push_back({n,t});
}
}
void ShortestPaths(int v)
{
int k=0;//从首个节点开始访问
int t;
G.vexs[v].length=0;
q.push(G.vexs[v].data);
while(!q.empty())
{
t=q.front();
for(int i=0,j=G.arcs[t].size(); i<j; i++)
{
k=G.arcs[t][i].u;
printf("%d------%d\n",t,k);
if(G.vexs[t].length+G.arcs[t][i].info<=G.vexs[k].length)//减枝操作
{
G.vexs[k].length=G.vexs[t].length+G.arcs[t][i].info;
q.push(G.vexs[k].data);
}
}
q.pop();
}
}
void Print()
{
for(int i=1;i<=G.vexnum;i++)
printf("%d------%d\n",G.vexs[i].data,G.vexs[i].length);
}
int main()
{
CreateGraph();
ShortestPaths(1);
Print();
return 0;
}
|