用分支定界算法求以下问题:
某公司于乙城市的销售点急需一批成品, 该公司成品生产基地在甲城市。甲城市与乙城市之间共有 n 座城市,互相以公路连通。甲城市、乙城市以及其它各城市之间的公路连通情况及每段公路的长度由矩阵M1 给出。每段公路均由地方政府收取不同额度的养路费等费用, 具体数额由矩阵 M2 给出。请给出在需付养路费总额不超过 1500 的情况下,该公司货车运送其
产品从甲城市到乙城市的最短运送路线。
具体数据参见文件:
M1.txt: 各城市之间的公路连通情况及每段公路的长度矩阵(有向图); 甲城市为城市 Num.1,乙城市为城市 Num.50。(9999表示不连通)
M2.txt: 每段公路收取的费用矩阵(非对称)。
解题思路:
利用Length_bound[i]和Cost_bound[i]记录搜索过程中到该城市路线总长度和总花费都最小的
界,再搜索到该城市时,如果其长度和花费均大于bound,则剪枝,如果长度和花费均小于bound,
则更新bound(该bound主要为了避免陷入自环)
利用Dijkstra算法分别找出从终点城市出发到所有其他城市的最短路径长度Min_Length[i]以
及最小花费Min_Cost[i],并以此也作为bound。
再从起点城市出发,利用DFS进行路径搜索,每前进一个城市,判断已走路径长度与当前城市
到终点的最短路径之和Sum_Length + Min_Length[i]是否大于已经搜索到的当前最优路线的路径
长度Best_Length,若大于则无需向下搜索,否则再比较已走路径花费与前城市到终点的最小花费
之和Sum_Cost + Min_Cost[i]是否大于1500,若大于则无需向下搜索。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <vector>
#include <queue>
#include <time.h>
#define City_Num 50 //城市的数量
#define N_MAX (City_Num + 1) //定义邻接矩阵的大小为城市数量+1
#define INF (0x3f3f3f3f)
using namespace std;
struct Port {
int ID; //节点的序号
int Sum_Length; //从起点出发至该节点走过的路程
Port(int id, int Length) {
ID = id; Sum_Length = Length;
}
bool operator <(const Port& s)const {
return Sum_Length > s.Sum_Length; //按照走过的路径长度排序,最小堆
}
};
struct Edge {
int to;
int length;
int price;
Edge(int too, int lengthh, int pricee) {
to = too; length = lengthh; price = pricee;
}
};
//vector<Edge>City[N_MAX]; //定义邻接链表
int Road[N_MAX][N_MAX], Value[N_MAX][N_MAX]; //定义邻接矩阵
int Min_Length[N_MAX], Min_Cost[N_MAX]; //定义由终点出发到到其他城市的最短路径长度以及最小花费
int Length_bound[N_MAX], Cost_bound[N_MAX]; //长度和花费bound
bool Flag[N_MAX]; //1表示已经搜索过该城市
int Result[N_MAX], Search[N_MAX]; //输出的最短路线,当前搜索的路线
int Best_Length = 9999; //定义最短可行路径总长度
void Dijkstra_Len(int Start);
void Dijkstra_Cost(int Start);
/*
num:为搜索到的第几层
Sum_Length:已走路径总长
Sum_Cost:已走路径花费
*/
int K = 0;
void DFS(int num, int Sum_Length, int Sum_Cost)
{
int front = Search[num];
if (front == City_Num)
{
if (Sum_Length < Best_Length) //比最好的好,更新
{
for (int i = 1; i <= num; i++)
{
Result[i] = Search[i];
//cout << Result[i] << ' ';
}
Best_Length = Sum_Length;
//cout << endl << "len = " << Best_Length << " cost = " << Sum_Cost << endl;
}
return;
}
for (int i = 1; i < N_MAX; i++) //松弛操作
{
if (Road[front][i] != 9999)
{
//cout <<"asf = " << i << endl;
int SUM_L = Sum_Length + Road[front][i]; //路径总长
int SUM_C = Sum_Cost + Value[front][i]; //总花费
if (SUM_L + Min_Length[i] >= Best_Length) //第一个bound
//if (SUM_L >= Best_Length)
continue;
if (SUM_C + Min_Cost[i] > 1500) //第二个bound
//if (SUM_C > 1500)
continue;
//第三个bound,主要避免在环内循环搜索
if (SUM_L >= Length_bound[i] && //长度和花费均大于bound,剪枝
SUM_C >= Cost_bound[i])
{
continue;
}
else if (SUM_L < Length_bound[i] && //长度和花费均小于bound,更新bound
SUM_C < Cost_bound[i])
{
Length_bound[i] = SUM_L;
Cost_bound[i] = SUM_C;
}
Search[num + 1] = i;
K++;
DFS(num + 1, SUM_L, SUM_C);
}
}
}
int main()
{
int N, M;
clock_t start, stop; //定义clock_t类型的start和end
ifstream road("m1.txt");
ifstream value("m2.txt");
for (int i = 1; i < N_MAX; ++i)
{
for (int j = 1; j < N_MAX; ++j)
{
road >> N;
value >> M;
Road[i][j] = N;
Value[i][j] = M;
//if (N != 9999) //9999即可视为不连通
//{
// Edge E(j,N,M);
// City[i].push_back(E);
//}
}
}
start = clock();
Dijkstra_Len(City_Num);
Dijkstra_Cost(City_Num);
memset(Length_bound, INF, sizeof(Length_bound));
memset(Cost_bound, INF, sizeof(Cost_bound));
Search[1] = 1;
DFS(1, 0, 0);
stop = clock();
cout << "算法运行时间 = " << (double)(stop - start) / CLOCKS_PER_SEC << endl;
cout << "搜索次数 = " << K << endl;
cout << "最小路径总长度 = " << Best_Length << endl << "最佳路线: ";
for (int i = 1; Result[i] != City_Num && i<= N_MAX; ++i)
{
cout << Result[i] << ' ' ;
}
cout << 50 << endl;
return 0;
}
//找出从终点城市出发到所有其他城市的最短路径长度Min_Length[i]
void Dijkstra_Len(int Start)
{
memset(Min_Length, INF, sizeof(Min_Length));
Min_Length[Start] = 0;
memset(Flag, 0, sizeof(Flag));
priority_queue<Port>Save;
Save.push(Port(Start, Min_Length[Start]));
while (!Save.empty())
{
Port Front = Save.top(); //上一个到达的点
Save.pop();
if (Flag[Front.ID]) //该城市已经搜索过
continue;
Flag[Front.ID] = 1;
/*
for (int i = 0; i < City[Front.ID].size(); i++) //松弛操作
{
Edge E = City[Front.ID][i];
if (!Flag[E.to])
{
if (Min_Length[E.to] > Min_Length[Front.ID] + E.length)
{
Min_Length[E.to] = Min_Length[Front.ID] + E.length;
Save.push(Port(E.to, Min_Length[E.to]));
}
}
}
*/ //邻接链表
for (int i = 1; i < N_MAX; i++) //松弛操作
{
if (Road[i][Front.ID] != 9999)
{
//cout << City[Front.ID][i].length << ' '<< City[Front.ID][i].price << endl;
if (!Flag[i])
{
if (Min_Length[i] > Min_Length[Front.ID] + Road[i][Front.ID])
{
Min_Length[i] = Min_Length[Front.ID] + Road[i][Front.ID];
Save.push(Port(i, Min_Length[i]));
}
}
}
}
}
}
//找出从终点城市出发到所有其他城市的最小花费Min_Cost[i]
void Dijkstra_Cost(int Start)
{
memset(Min_Cost, INF, sizeof(Min_Cost));
Min_Cost[Start] = 0;
memset(Flag, 0, sizeof(Flag));
priority_queue<Port>Save;
Save.push(Port(Start, Min_Cost[Start]));
while (!Save.empty())
{
Port Front = Save.top(); //上一个到达的点
Save.pop();
if (Flag[Front.ID]) //该城市已经搜索过
continue;
Flag[Front.ID] = 1;
for (int i = 1; i < N_MAX; i++) //松弛操作
{
if (Road[i][Front.ID] != 9999)
{
//cout << City[Front.ID][i].length << ' '<< City[Front.ID][i].price << endl;
if (!Flag[i])
{
if (Min_Cost[i] > Min_Cost[Front.ID] + Value[i][Front.ID])
{
Min_Cost[i] = Min_Cost[Front.ID] + Value[i][Front.ID];
Save.push(Port(i, Min_Cost[i]));
}
}
}
}
}
}