const int maxNum = 0x3f3f3f3f; // 定义一个足够大的数,代表图中两顶点间无边
class graph
{
private:
int V;
public:
vector > g;
graph(int V)
{
this->V = V;
// g为二维数组,里面每个元素初始化为无穷大
g = vector >(V, vector(V, maxNum));
}
~graph(){};
int getV() { return V; }
void addEdge(int s, int t, int w);
};
void graph::addEdge(int s, int t, int w) {
g[s][t] = w;
g[t][s] = w;
}
\quad 图有V个顶点,默认标号为0到V-1。这样,我们就可以通过调用addEdge给图添加从是s点到t点权重为w的一条边。
如果我们要建立如下图所示这样一个图,我们把a点看作0,b点看作7,则建图过程为:
int main()
{
graph G(8);
G.addEdge(0, 1, 2);
G.addEdge(0, 2, 8);
G.addEdge(0, 3, 1);
G.addEdge(1, 2, 6);
G.addEdge(1, 4, 1);
G.addEdge(2, 3, 7);
G.addEdge(2, 4, 4);
G.addEdge(2, 5, 2);
G.addEdge(2, 6, 2);
G.addEdge(3, 6, 9);
G.addEdge(4, 5, 3);
G.addEdge(4, 7, 9);
G.addEdge(5, 6, 4);
G.addEdge(5, 7, 6);
G.addEdge(6, 7, 2);
return 0;
}
\quad 我们先来看看初始化和大体框架,最后再来写算法的核心部分。
class Dantjig
{
private:
graph &G;
int v; // 起始点
bool *visited; // 判断顶点是否已标号
int *t; // 顶点的标号值,表示初始点到当前点的最短路长度
vector A; // 访问过的顶点集合
vector > T; // 访问过的边集合,用于输出路劲
public:
Dantjig(graph &graph, int v): G(graph)
{
// 初始化各个变量
visited = new bool[G.getV()];
t = new int[G.getV()];
for (int i = 0; i < G.getV(); ++i) {
visited[i] = false;
t[i] = 0;
}
this->v = v;
A.clear();
_Dantjig(v); // 算法核心
}
~Dantjig()
{
delete[] visited;
delete[] t;
A.clear();
T.clear();
}
void _Dantjig(int v); // 申明算法
// 返回v点到w点的最短距离
int minLen(int w)
{
return t[w];
}
// 找出顶点to对应的另一个顶点from
int getfrom(int to)
{
for (int i = 0; i < T.size(); ++i) {
if(T[i].second==to) return T[i].first;
}
}
// 打印路径
void showpath(int w)
{
stack s;
int from = getfrom(w);
while(from!=v)
{
s.push(from);
from = getfrom(from);
}
s.push(v);
while(!s.empty())
{
cout << s.top() << "->";
s.pop();
}
cout << w << endl;
}
};
\quad 在类的成员变量中A是已被标记的点,T是访问过的边的集合。上图中如果以a点为起点,b点为终点输入,运形程序后, T = { ( 0 , 3 ) ( 0 , 1 ) ( 1 , 4 ) ( 4 , 5 ) ( 4 , 2 ) ( 2 , 6 ) ( 6 , 7 ) } T=\{(0,3) (0,1) (1,4) (4,5) (4,2) (2,6) (6,7)\} T={(0,3)(0,1)(1,4)(4,5)(4,2)(2,6)(6,7)}。getfrom函数就是找出T中一条边中后面一个点的前一个点。比如要找出7这个点对应的点6,就可以用getfrom得到。showpath即可从终点开始,在T中不断搜索前一个节点,存在栈stack中,之后输出即为起点到终点的路劲。
void Dantjig::_Dantjig(int v) {
A.push_back(v);
if(A.size()==G.getV()) // 图中所有顶点均已标记,结束递归
return;
visited[v] = true;
int minWeight = maxNum; // 存储当前结点下相邻节点中拥有的最短的边长度
int minV; // 存放下一个被标记的顶点
int from, to; // 记录路劲
for (int i = 0; i < A.size(); ++i) {
for (int j = 0; j < G.getV(); ++j) {
if(!visited[j] && G.g[A[i]][j]!=maxNum)
{
int temp = t[A[i]];
if(temp+G.g[A[i]][j] < minWeight)
{
minWeight = temp+G.g[A[i]][j];
minV = j;
from = A[i];
to = j;
}
}
}
}
T.push_back(make_pair(from, to));
t[minV] = minWeight; // 更新起始点到该点的最短路劲值
_Dantjig(minV); // 递归调用即可
}
//
// Created by 程勇 on 2019/3/7.
//
#include
using namespace std;
const int maxNum = 0x3f3f3f3f; // 定义一个足够大的数,代表图中两顶点间无边
class graph
{
private:
int V;
public:
vector > g;
graph(int V)
{
this->V = V;
// g为二维数组,里面每个元素初始化为无穷大
g = vector >(V, vector(V, maxNum));
}
~graph(){};
int getV() { return V; }
void addEdge(int s, int t, int w);
};
void graph::addEdge(int s, int t, int w) {
g[s][t] = w;
g[t][s] = w;
}
class Dantjig
{
private:
graph &G;
int v; // 起始点
bool *visited; // 判断顶点是否已标号
int *t; // 顶点的标号值,表示初始点到当前点的最短路长度
vector A; // 访问过的顶点集合
vector > T; // 访问过的边集合,用于输出路劲
public:
Dantjig(graph &graph, int v): G(graph)
{
// 初始化各个变量
visited = new bool[G.getV()];
t = new int[G.getV()];
for (int i = 0; i < G.getV(); ++i) {
visited[i] = false;
t[i] = 0;
}
this->v = v;
A.clear();
_Dantjig(v); // 算法核心
}
~Dantjig()
{
delete[] visited;
delete[] t;
A.clear();
T.clear();
}
void _Dantjig(int v); // 申明算法
// 返回v点到w点的最短距离
int minLen(int w)
{
return t[w];
}
// 找出顶点to对应的另一个顶点from
int getfrom(int to)
{
for (int i = 0; i < T.size(); ++i) {
if(T[i].second==to) return T[i].first;
}
}
// 打印路径
void showpath(int w)
{
stack s;
int from = getfrom(w);
while(from!=v)
{
s.push(from);
from = getfrom(from);
}
s.push(v);
while(!s.empty())
{
cout << s.top() << "->";
s.pop();
}
cout << w << endl;
}
};
void Dantjig::_Dantjig(int v) {
A.push_back(v);
if(A.size()==G.getV()) // 图中所有顶点均已标记,结束递归
return;
visited[v] = true;
int minWeight = maxNum; // 存储当前结点下相邻节点中拥有的最短的边长度
int minV; // 存放下一个被标记的顶点
int from, to; // 记录路劲
for (int i = 0; i < A.size(); ++i) {
for (int j = 0; j < G.getV(); ++j) {
if(!visited[j] && G.g[A[i]][j]!=maxNum)
{
int temp = t[A[i]];
if(temp+G.g[A[i]][j] < minWeight)
{
minWeight = temp+G.g[A[i]][j];
minV = j;
from = A[i];
to = j;
}
}
}
}
T.push_back(make_pair(from, to));
t[minV] = minWeight; // 更新起始点到该点的最短路劲值
_Dantjig(minV); // 递归调用即可
}
int main()
{
graph G(8);
G.addEdge(0, 1, 2);
G.addEdge(0, 2, 8);
G.addEdge(0, 3, 1);
G.addEdge(1, 2, 6);
G.addEdge(1, 4, 1);
G.addEdge(2, 3, 7);
G.addEdge(2, 4, 4);
G.addEdge(2, 5, 2);
G.addEdge(2, 6, 2);
G.addEdge(3, 6, 9);
G.addEdge(4, 5, 3);
G.addEdge(4, 7, 9);
G.addEdge(5, 6, 4);
G.addEdge(5, 7, 6);
G.addEdge(6, 7, 2);
Dantjig dantjig(G, 0);
// 输出a到b(即0到7)的最短距离
cout << dantjig.minLen(7) << endl;
dantjig.showpath(7); // 打印路径
return 0;
}