图的最短路径问题
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; }
相关文章推荐
- 【Dongle】【机房合作】之个人感谢
- C++中operator关键字(重载操作符)
- 第二个冲刺
- JAVA学习笔记整理九(IO)
- 集合框架-静态导入
- 改动opencv配置
- 设计模式之单例
- 网页设计之初学CSS
- mac 安装jupyter notebook
- linux小记:恍然大明白,sed命令中[commands]的格式
- 配置Scala环境出现:找不到或无法加载主类 scala.tools.nsc.MainGenericRunner
- 【MyBatis框架点滴】——MyBatis延迟加载
- 修改状态栏iOS
- el标签
- Next RunLoop
- 黯淡蓝点:旅行者号64亿公里外回望地球...
- CentOS中Intel i350T4驱动安装
- 实现四个数,前两个相同,后两个相同,并且是一个整数的平方
- HTML5之触摸事件(touchstart、touchmove和touchend)
- 教育的基因就是要自己实践或快速结合