您的位置:首页 > 其它

图的最短路径问题

2016-06-05 21:41 375 查看
<pre name="code" class="cpp">#include <iostream>
#include <cassert>
#include <vector>
#include <stack>
#include <functional>
#include <iterator>

using namespace std;

/*左右的图都使用邻接矩阵(vector<vector<int>>)的表示方法*/

/*Dijkstra算法:设图的顶点集合为U,已确定到原点s的最短路径的顶点集合为S。每次在U-S中选择一个离s最近的顶点v(dist[v]最小)加入S,接着遍历U-S中所有顶点,如果其经过v到达s
更近,那么更新其到s的最短距离dist[i]*/
/*s为源点,dist[i]为顶点i到s的最短距离,prev[i]保存到顶点i到s的最短路径的前驱顶点*/
//dijkstra算法只支持权值为正的图
void dijkstra(const vector<vector<int>>& graph, int s, vector<int>& dist, vector<int>& prev)
{
size_t nVertex = graph.size();
dist.resize(nVertex);
prev.resize(nVertex);
vector<bool> isVisited(nVertex, false);
for (size_t i = 0; i < nVertex; ++i)//初始化dist[i]为顶点i到s的距离
{
dist[i] = graph[s][i];
if (dist[i] != INT_MAX)
{
prev[i] = s;//如果i与s相邻则prev[i]=s
}
else
{
prev[i] = -1;//如果i与s不相邻则prev[i]=-1
}
}

isVisited[s] = true;//在集合S中的顶点都会被标记
prev[s] = -1;

//每次循环,S中会增加一个顶点,所以只要循环nVertex-1次
int count = nVertex - 1;
while (count-- > 0)
{
int selected = -1, minDistance = INT_MAX;
//找出距离s最近的顶点selected
for (size_t i = 0; i < nVertex; ++i)
{
if (!isVisited[i])
{
if (dist[i] < minDistance)
{
minDistance = dist[i];
selected = i;
}
}
}
isVisited[selected] = true;//将selected加入集合S
//
//更新dist,看看U-S中的顶点经过selected到达s是不是更短
//很傻瓜的做法就是对于U-S中的一个顶点,遍历它经过S中的每个顶点到大s会不会更短,然而并不需要遍历S中的每个点,只需要判断
//刚加入的那个顶点就好了,因为更早前加入S的顶点已经被判断过了
for (size_t j = 0; j < nVertex; ++j)
{
if (!isVisited[j])
{
if (graph[selected][j] != INT_MAX && dist[j] > dist[selected] + graph[selected][j])
{
dist[j] = dist[selected] + graph[selected][j];
prev[j] = selected;
}
}
}
}
}

void printRoute(const vector<int>& prev, const vector<int>& dist, int s)
{
for (size_t i = 0; i < prev.size(); ++i)
{
if (i != s)
{
for (int j = i; j != -1; j = prev[j])
{
cout << j << "  ";
}
cout << endl;
}
}
}

/*最小生成树prim算法:设图的顶点集合为U,最小生成树集合为S,任取一个顶点加入到S。每次在U-S中选择一个离S最近的顶点v加入S,直到U-S为空*/
int prim(const vector<vector<int>>& graph, vector<int>& route)//返回最小生成树的边缘权值和
{
size_t nVertex = graph.size();
vector<bool> isVisited(nVertex, false);
vector<int> dist(nVertex);//dist[i]表示顶点i距离集合S最近距离(距离集合S中所有点的最近距离)
isVisited[0] = true;
route.reserve(nVertex);
route.push_back(0);
dist[0] = 0;
for (size_t i = 1; i < nVertex; ++i)
{
dist[i] = graph[0][i];
}
int cost = 0;
//每次循环,S中会增加一个顶点,所以只要循环nVertex-1次
int count = nVertex - 1;
while (count-- > 0)
{
int selected = -1, minDistance = INT_MAX;
//找出距离集合S最近的顶点
for (size_t i = 0; i < nVertex; ++i)
{
if (!isVisited[i])
{
if (dist[i] < minDistance)
{
minDistance = dist[i];
selected = i;
}
}
}
cost += minDistance;
isVisited[selected] = true;
route.push_back(selected);
//
//更新dist,在U-S中找出距离集合S最近的顶点(距离集合中每个元素最近距离),只要比较每个顶点与刚加入的顶点即可,因为U-S中顶点与S
//中其它顶点的最短距离早前已经计算过
for (size_t j = 0; j < nVertex; ++j)
{
if (!isVisited[j])
{
dist[j] = dist[j] > graph[selected][j] ? graph[selected][j] : dist[j];
}
}
}

return cost;
}

/*floyd解决任意两点之间的最短距离,动态规划,
for k in vertex
if Dis(i,k) + Dis(k,j) < Dis(i,j)
Dis(i,j) = Dis(i,k) + Dis(k,j)
这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离*/
void floyd(const vector<vector<int>>& graph, vector<vector<int>>& dists, vector<vector<int>>& path)
{
//path[i][j]存储最短路径i->j中顶点j的前驱
size_t n = graph.size();
path.resize(n);
for (size_t i = 0; i < n; ++i)
{
path[i].resize(n);
for (size_t j = 0; j < n; ++j)
{
if (graph[i][j] == INT_MAX)
{
path[i][j] = -1;
}
else {
path[i][j] = i; //初始化为i,因为
}
}
}
std::copy(graph.begin(), graph.end(), std::back_inserter(dists));

for (int k = 0; k < n; ++k)//k一定要放在最外面
{
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (dists[i][k] != INT_MAX && dists[k][j] != INT_MAX && dists[i][k] + dists[k][j] < dists[i][j])
{
dists[i][j] = dists[i][k] + dists[k][j];
path[i][j] = k;
}
}
}
}
}

void printPath(const vector<vector<int>>& path, int from, int to)
{
if (path[from][to] == -1)
{
cout << "No path" << endl;
return;
}

if (path[from][to] != from)
{
printPath(path, from, path[from][to]);
}
cout << path[from][to] << "->" << to << " ";
}

int _tmain(int argc, char* argv[])
{
int a[] = {0, 13, 8, INT_MAX, 30, INT_MAX, 32,
INT_MAX, 0, INT_MAX, INT_MAX, INT_MAX, 9, 7,
INT_MAX, INT_MAX, 0, 5, INT_MAX, INT_MAX, INT_MAX,
INT_MAX, INT_MAX, INT_MAX, 0, 6, INT_MAX, INT_MAX,
INT_MAX, INT_MAX, INT_MAX, INT_MAX, 0, 2, INT_MAX,
INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, 0, 17,
INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX, 0};
int* p = a;
//输入一个图
int nRows = 7, nCols = 7;
vector<vector<int>> graph(nRows, vector<int>(nCols));
for (size_t i = 0; i < nRows; ++i)
{
for (size_t j = 0; j < nCols; ++j)
{
graph[i][j] = *(p++);
}
}

vector<int> dist, prev;
dijkstra(graph, 0, dist, prev);
printRoute(prev, dist, 0);

vector<int> route;
cout << "cost of prim = " << prim(graph, route) << endl;
cout << "prim = " << endl;
for (auto r : route)
{
cout << r << "  ";
}
cout << endl;

cout << "path of route floyd" << endl;
vector<vector<int>> dists, path;
floyd(graph, dists, path);

printPath(path, 4, 6);

system("pause");
return 0;
}



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: