#include
#include
#include
#include
using namespace std;
map<int , vectorint , int, double>>> EWD;
int main()
{
int V, E;
cin >> V >> E;
for(int i = 0 ; i < E ;i++)
{
int v, w;
double weight;
cin >> v >> w >> weight;
EWD[v].push_back(make_tuple(v, w, weight));
}
cout << "EdgeWeightedDigraph : " << endl;
for(int v = 0; v < V; v++)
{
cout << v << " : ";
for(vectorint , int, double>>::iterator ii = EWD[v].begin(); ii != EWD[v].end(); ii++)
cout << get<0>(*ii) << "->" << get<1>(*ii) << " " << get<2>(*ii) << " ";
cout << endl;
}
system("pause");
}
测试数据来源见引用[1]
文件结构:
V //顶点数
E // 边数
v w weight // 顶点 顶点 权重
数据内容:
8
15
4 5 0.35
5 4 0.35
4 7 0.37
5 7 0.28
7 5 0.28
5 1 0.32
0 4 0.38
0 2 0.26
7 3 0.39
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93
EdgeWeightedDigraph :
0 : 0->4 0.38 0->2 0.26
1 : 1->3 0.29
2 : 2->7 0.34
3 : 3->6 0.52
4 : 4->5 0.35 4->7 0.37
5 : 5->4 0.35 5->7 0.28 5->1 0.32
6 : 6->2 0.4 6->0 0.58 6->4 0.93
7 : 7->5 0.28 7->3 0.39
//引入 C++ STL tuple 类型
#include
//顶点v -> 顶点w 权重weight
tuple<int, int, double>
//创建tuple对象
make_tuple(v, w, weight)
//获取tuple类型中的数据
get<0>(a_tuple_object) // v
get<1>(a_tuple_object) // w
get<2>(a_tuple_object) // weight
// 引入 vector 类型 和 map
#include
#include
// 邻接表表示法 表示 有向图
// int : 顶点编号
// vector : 一个带权有向边的集合
map<int , vectorint , int, double>>> EWD;
// 向图中添加边
// 邻接表表示法(直观点,看上方运行结果)
EWD[v].push_back(make_tuple(v, w, weight));
map
(哈希表);vector
列表,列表本质是一些带权重的有向边;v
顶点(from
),w
顶点(to
)以及权重weight
,代码实现是一个tuple
,就是把三个不同类型的数据“绑”在一起;Dijstra算法求解单源最短路径问题,要求边权重非负。
Dijkstra's algorithm initializing dist[s] to 0 and all other distTo[] entries to positive infinity. Then, it repeatedly relaxes and adds to the tree a non-tree vertex with the lowest distTo[] value, continuing until all vertices are on the tree or no non-tree vertex has a finite distTo[] value.(参考[2])
生成一个最短路径树:
1. 首先指定一个 起点 ,将 起点 加入最短路径树,放松 起点 指出的所有边;
2. 选取 最短路径树顶点集合 指出的所有边 中离起点最近的那条,将 那条边 指向的 非树顶点 加入最短路径树,放松 其 指出 所有的边;
3. 重复步骤2;
4. 直到 所有顶点 加入最短路径树,算法终止。
//初始条件
dist[source] = 0; // 起点的距离置为 0
dist[othetrs] = +∞;
// 说明
distTo[w] // from s to w , sum of weight
edgeTo[w] // last edge to w
Minpq 见[3]
// relax 放松
假设起点 s 到达某个顶点 w 的distTo[w]已知了, 不妨看做是s->w ;
这时候发现如果 s 绕路到 v 再去 w 会更“近”,那么就走s->v->w,更新distTo[w],edgeTo[w] = v ;
直到从s出发可达的全部顶点的最短路径计算完毕,算法终止.
distTo[]
记录的是,到达w为止的总长度;edgeTo[]
记录的是,路径上的最后一个顶点(在algs4的实现代码中,记录的是最后一条边edge);参考algs4 DijkstraSP.java实现 具体见参考[2]
#include
#include
#include
#include
#include
#include
using namespace std;
double distTo[100];
int edgeTo[100];
int V, E;
const double INF_MAX = 9999999.9;
map<int , vectorint , int, double>>> EWD;
struct GreaterThanByDist
{
bool operator()(const int i, const int j) const
{
return distTo[i] > distTo[j];
}
};
priority_queue<int, vector<int>, GreaterThanByDist> Minpq;
void relax(tuple<int, int, double> edge)
{
int v = get<0>(edge);
int w = get<1>(edge);
double weight = get<2>(edge);
if (distTo[w] > distTo[v] + weight) {
distTo[w] = distTo[v] + weight;
edgeTo[w] = v;
Minpq.push(w);
}
}
void DijkstraSP(int s,int V)
{
for(int v = 0 ; v < V; v++)
distTo[v] = INF_MAX;
distTo[s] = 0.0;
Minpq.push(s);
while(!Minpq.empty())
{
int v = Minpq.top();
Minpq.pop();
for(vectorint , int, double>>::iterator ii = EWD[v].begin();
ii != EWD[v].end();
ii++)
{ relax(*ii); }
}
}
void computeSP(int source, int vertex)
{
cout << "shortest path : ";
DijkstraSP(source, V);
cout << source << " to " << vertex << " ( " << distTo[vertex] << " ) " << " : " ;
stack<int> path;
for(int i = vertex; i != source; i = edgeTo[i])
path.push(i);
path.push(source);
while(!path.empty())
{
cout << path.top() << " ";
path.pop();
}
cout << endl;
}
void showEWD()
{
cout << "EdgeWeightedDigraph : " << endl;
for(int v = 0; v < V; v++)
{
cout << v << " : ";
for(vectorint , int, double>>::iterator ii = EWD[v].begin();
ii != EWD[v].end();
ii++)
{ cout << get<0>(*ii) << "->" << get<1>(*ii) << " " << get<2>(*ii) << " "; }
cout << endl;
}
}
int main()
{
cin >> V >> E;
for(int i = 0 ; i < E ;i++)
{
int v, w;
double weight;
cin >> v >> w >> weight;
EWD[v].push_back(make_tuple(v, w, weight));
}
//showEWD();
int source, vertex;
cout << "source : ";
cin >> source;
cout << "vertex : ";
cin >> vertex;
for(int i = 0; i < V; i++)
computeSP(source, i);
system("pause");
}
source :
0
vertex :
7
shortest path : 0 to 0 ( 0 ) : 0
shortest path : 0 to 1 ( 1.05 ) : 0 4 5 1
shortest path : 0 to 2 ( 0.26 ) : 0 2
shortest path : 0 to 3 ( 0.99 ) : 0 2 7 3
shortest path : 0 to 4 ( 0.38 ) : 0 4
shortest path : 0 to 5 ( 0.73 ) : 0 4 5
shortest path : 0 to 6 ( 1.51 ) : 0 2 7 3 6
shortest path : 0 to 7 ( 0.6 ) : 0 2 7
Prime
算法,可以这样理解,首先任意选定顶点{0}
,距离这个集合最近的边比如0-1
边被选入,集合变成{0,1}
,接着距离这个集合最近的边比如0-3
边被选入,集合变成{0,1,3}
,最后距离这个集合最近的边2-3
边被选择,集合成为{0,1,2,3}
,算法终止。Dijkstra
算法,可以这样理解,首先必须指定起点{0}
,距离起点最近的顶点1被选入,集合变成{0,1}
,然后距离起点最近的是顶点3,,集合变成{0,1,3}
,最后距离起点最近的是顶点2,集合变成{0,1,2,3}
;MST
最小生成树看的是新加入的顶点到集合这个整体的距离;SP
最短路径看的是顶点到起点的距离;Dijkstra
只要舍去放松操作,就可以看做是Prim
算法,能够拿来求解MSTMST
最小生成树 并不能保证任意两点之间距离最短 ,MST追求永远的总的权重最小,也就是走遍全部顶点的路径长度最短;SP
最短路径或者更准确的说法是 某个指定的起点到达其他点的路径最短 ,追求的是从某个具体点出发, 这个具体点到达任意点的路径都是最短的;MST
和SP
最终的边的集合是有可能相同的,但是这是一种巧合。[1] http://algs4.cs.princeton.edu/44sp/tinyEWD.txt
[2] DijkstraSP.java
http://algs4.cs.princeton.edu/44sp/
http://algs4.cs.princeton.edu/44sp/DijkstraSP.java
[3] [C++]C++ STL priority_queue IndexPriorityQueue 索引优先队列 比较器
http://blog.csdn.net/cook2eat/article/details/52455647