当前位置: 首页 > news >正文

网站后台导入excel表格如何实现输入域名访问网站首页

网站后台导入excel表格,如何实现输入域名访问网站首页,百度旧版本,90做网站目录 一.图的基本概念 二.图的存储结构 1.邻接矩阵 2.邻接表 三.图的遍历 1.图的广度优先遍历 2.图的深度优先遍历 四.最小生成树 1.Kruskal算法 2.Prim算法 五.最短路径 1.单源最短路径--Dijkstra算法 2.单源最短路径--Bellman-Ford算法 3.多源最短路径--Floyd-…目录 一.图的基本概念 二.图的存储结构 1.邻接矩阵 2.邻接表 三.图的遍历 1.图的广度优先遍历 2.图的深度优先遍历 四.最小生成树 1.Kruskal算法 2.Prim算法 五.最短路径 1.单源最短路径--Dijkstra算法 2.单源最短路径--Bellman-Ford算法 3.多源最短路径--Floyd-Warshall算法 六.整体实现 1.UnionFindSet.h 2.Graph.h 3.test.cpp 一.图的基本概念 图是由顶点集合及顶点间的关系组成的一种数据结构G (V E)其中 顶点集合V {x|x属于某个数据对象集}是有穷非空集合 E {(x,y)|x,y属于V}或者E {|x,y属于V Path(x, y)}是顶点间关系的有穷集合也叫做边的集合 (x, y)表示x到y的一条双向通路即(x, y)是无方向的Path(x, y)表示从x到y的一条单向通路即Path(x, y)是有方向的 顶点和边图中结点称为顶点第i个顶点记作vi。两个顶点vi和vj相关联称作顶点vi和顶点vj之间有一条边图中的第k条边记作ekek (vivj)或vivj 有向图和无向图在有向图中顶点对是有序的顶点对xy称为顶点x到顶点y的一条边(弧)和是两条不同的边比如下图G3和G4为有向图。在无向图中顶点对(x, y) 是无序的顶点对(x,y)称为顶点x和顶点y相关联的一条边这条边没有特定方向(x, y)和(yx) 是同一条边比如下图G1和G2为无向图。注意无向边(x, y)等于有向边和 完全图在有n个顶点的无向图中若有n * (n-1)/2条边即任意两个顶点之间有且仅有一条边 则称此图为无向完全图比如上图G1在n个顶点的有向图中若有n * (n-1)条边即任意两个顶点之间有且仅有方向相反的边则称此图为有向完全图比如上图G4 邻接顶点在无向图中G中若(u, v)是E(G)中的一条边则称u和v互为邻接顶点并称边(u,v)依附于顶点u和v在有向图G中若是E(G)中的一条边则称顶点u邻接到v顶点v邻接自顶 点u并称边与顶点u和顶点v相关联 顶点的度顶点v的度是指与它相关联的边的条数记作deg(v)。在有向图中顶点的度等于该顶点的入度与出度之和其中顶点v的入度是以v为终点的有向边的条数记作indev(v);顶点v的出度是以v为起始点的有向边的条数记作outdev(v)。因此dev(v) indev(v) outdev(v)。注 意对于无向图顶点的度等于该顶点的入度和出度即dev(v) indev(v) outdev(v) 路径在图G (V E)中若从顶点vi出发有一组边使其可到达顶点vj则称顶点vi到顶点vj的顶点序列为从顶点vi到顶点vj的路径 路径长度对于不带权的图一条路径的路径长度是指该路径上的边的条数对于带权的图一 条路径的路径长度是指该路径上各个边权值的总和 简单路径与回路若路径上各顶点v1v2v3…vm均不重复则称这样的路径为简单路 径。若路径上第一个顶点v1和最后一个顶点vm重合则称这样的路径为回路或环 子图设图G {V, E}和图G1 {V1E1}若V1属于V且E1属于E则称G1是G的子图 连通图在无向图中若从顶点v1到顶点v2有路径则称顶点v1与顶点v2是连通的。如果图中任意一 对顶点都是连通的则称此图为连通图 强连通图在有向图中若在每一对顶点vi和vj之间都存在一条从vi到vj的路径也存在一条从vj到vi的路径则称此图是强连通图 生成树一个连通图的最小连通子图称作该图的生成树。有n个顶点的连通图的生成树有n个顶点和n1条边 二.图的存储结构 1.邻接矩阵 因为节点与节点之间的关系就是连通与否即为0或者1因此邻接矩阵(二维数组)即是先用一 个数组将定点保存然后采用矩阵来表示节点与节点之间的关系 注意: 无向图的邻接矩阵是对称的第i行(列)元素之和就是顶点i的度。有向图的邻接矩阵则不一 定是对称的第i行(列)元素之后就是顶点i的出(入)度如果边带有权值并且两个节点之间是连通的上图中的边的关系就用权值代替如果两个 顶点不通则使用无穷大代替用邻接矩阵存储图的有点是能够快速知道两个顶点是否连通缺陷是如果顶点比较多边比 较少时矩阵中存储了大量的0成为系数矩阵比较浪费空间并且要求两个节点之间的路 径不是很好求 namespace matrix {templateclass V, class W, W MAX_W INT_MAX, bool Direction falseclass Graph{typedef GraphV, W, MAX_W, Direction Self;public://图的创建//1.IO输入-不方便测试,oj中更适合//2.图结构关系写到文件,读取文件//3.手动添加边Graph() default;Graph(const V* a, size_t n){_vertexs.reserve(n);for (size_t i 0; i n; i){_vertexs.push_back(a[i]);_indexMap[a[i]] i;}_matrix.resize(n);for (size_t i 0; i _matrix.size(); i){_matrix[i].resize(n, MAX_W);}}size_t GetVertexIndex(const V v){auto it _indexMap.find(v);if (it ! _indexMap.end()){return it-second;}else{//assert(false);throw invalid_argument(顶点不存在);return -1;}}void _AddEdge(size_t srci, size_t dsti, const W w){_matrix[srci][dsti] w;//无向图if (Direction false){_matrix[dsti][srci] w;}}void AddEdge(const V src, const V dst, const W w){size_t srci GetVertexIndex(src);size_t dsti GetVertexIndex(dst);_AddEdge(srci, dsti, w);}void Print(){//顶点for (size_t i 0; i _vertexs.size(); i){cout [ i ] - _vertexs[i] endl;}cout endl;//矩阵//横下标cout ;for (size_t i 0; i _matrix.size(); i){//cout i ;printf(%4d, i);}cout endl;for (size_t i 0; i _matrix.size(); i){cout i ;//竖下标for (size_t j 0; j _matrix[i].size(); j){//cout _matrix[i][j] ;if (_matrix[i][j] MAX_W){//cout * ;printf(%4c, *);}else{//cout _matrix[i][j] ;printf(%4d, _matrix[i][j]);}}cout endl;}cout endl;}private:vectorV _vertexs; //顶点集合mapV, int _indexMap; //顶点映射下标vectorvectorW _matrix; //邻接矩阵}; } void TestGraph1() {Graphchar, int g(0123, 4);//Graphchar, int, true g(0123, 4);g.AddEdge(0, 1, 1);g.AddEdge(0, 3, 4);g.AddEdge(1, 3, 2);g.AddEdge(1, 2, 9);g.AddEdge(2, 3, 8);g.AddEdge(2, 1, 5);g.AddEdge(2, 0, 3);g.AddEdge(3, 2, 6);g.Print(); } 邻接矩阵总结: 邻接矩阵存储方式非常适合稠密图邻接矩阵O(1)判断两个顶点的连接关系并取到权值相对而言不适合查找一个顶点连接所有边----O(N) 2.邻接表 邻接表使用数组表示顶点的集合使用链表表示边的关系 1.无向图邻接表存储         注意:无向图中同一条边在邻接表中出现了两次。如果想知道顶点vi的度只需要知道顶点vi边链表集合中结点的数目即可 2.有向图邻接表存储 注意:有向图中每条边在邻接表中只出现一次与顶点vi对应的邻接表所含结点的个数就是该顶点的出度也称出度表要得到vi顶点的入度必须检测其他所有顶点对应的边链表看有多少边顶点的dst取值是i namespace link_table {templateclass Wstruct Edge{//int _srci;int _dsti; //目标点的下标W _w; //权值EdgeW* _next;Edge(int dsti, const W w) :_dsti(dsti), _w(w), _next(nullptr){ }};templateclass V, class W, bool Direction falseclass Graph{typedef EdgeW Edge;public:Graph(const V* a, size_t n){_vertexs.reserve(n);for (size_t i 0; i n; i){_vertexs.push_back(a[i]);_indexMap[a[i]] i;}_tables.resize(n, nullptr);}size_t GetVertexIndex(const V v){auto it _indexMap.find(v);if (it ! _indexMap.end()){return it-second;}else{//assert(false);throw invalid_argument(顶点不存在);return -1;}}void AddEdge(const V src, const V dst, const W w){size_t srci GetVertexIndex(src);size_t dsti GetVertexIndex(dst);Edge* eg new Edge(dsti, w);eg-_next _tables[srci];_tables[srci] eg;if (Direction false){Edge* eg new Edge(srci, w);eg-_next _tables[dsti];_tables[dsti] eg;}}void Print(){//顶点for (size_t i 0; i _vertexs.size(); i){cout [ i ] - _vertexs[i] endl;}cout endl;for (size_t i 0; i _tables.size(); i){cout _vertexs[i] [ i ]-;Edge* cur _tables[i];while (cur){cout [ _vertexs[cur-_dsti] : cur-_dsti : cur-_w ]-;cur cur-_next;}cout nullptr endl;}}private:vectorV _vertexs; //顶点集合mapV, int _indexMap; //顶点映射下标vectorEdge* _tables; //邻接表}; } void TestGraph2() {string a[] { 张三, 李四, 王五, 赵六 };//Graphstring, int, true g1(a, 4);Graphstring, int g1(a, 4);g1.AddEdge(张三, 李四, 100);g1.AddEdge(张三, 王五, 200);g1.AddEdge(王五, 赵六, 30);g1.Print(); } 邻接表总结: 适合存储稀疏图适合查找一个顶点连接出去的边不适合确定两个顶点是否相连及权值 三.图的遍历 1.图的广度优先遍历 void BFS(const V src) {size_t srci GetVertexIndex(src);//队列和标记数组queueint q;vectorbool visited(_vertexs.size(), false);q.push(srci);visited[srci] true;int levelSize 1;size_t n _vertexs.size();while (!q.empty()){//一层一层出for (int i 0; i levelSize; i){int front q.front();q.pop();cout front : _vertexs[front] ;//把front顶点的邻接顶点入队列for (size_t i 0; i n; i){if (_matrix[front][i] ! MAX_W){if (visited[i] false){q.push(i);visited[i] true;}}}}cout endl;levelSize q.size();}cout endl; } void TestBDFS() {string a[] { 张三, 李四, 王五, 赵六, 周七 };Graphstring, int g1(a, sizeof(a) / sizeof(string));g1.AddEdge(张三, 李四, 100);g1.AddEdge(张三, 王五, 200);g1.AddEdge(王五, 赵六, 30);g1.AddEdge(王五, 周七, 30);g1.Print();g1.BFS(张三); } 2.图的深度优先遍历 void _DFS(size_t srci, vectorbool visited) {cout srci : _vertexs[srci] endl;visited[srci] true;//找一个和srci相邻的没有访问过的点,去深度遍历for (size_t i 0; i _vertexs.size(); i){if (_matrix[srci][i] ! MAX_W visited[i] false){_DFS(i, visited);}} }void DFS(const V src) {size_t srci GetVertexIndex(src);vectorbool visited(_vertexs.size(), false);_DFS(srci, visited); } void TestBDFS() {string a[] { 张三, 李四, 王五, 赵六, 周七 };Graphstring, int g1(a, sizeof(a) / sizeof(string));g1.AddEdge(张三, 李四, 100);g1.AddEdge(张三, 王五, 200);g1.AddEdge(王五, 赵六, 30);g1.AddEdge(王五, 周七, 30);g1.Print();g1.DFS(张三); } 四.最小生成树 连通图中的每一棵生成树都是原图的一个极大无环子图即从其中删去任何一条边生成树就不在连通反之在其中引入任何一条新边都会形成一条回路 若连通图由n个顶点组成则其生成树必含n个顶点和n-1条边。因此构造最小生成树的准则有三条: 只能使用图中的边来构造最小生成树只能使用恰好n-1条边来连接图中的n个顶点选用的n-1条边不能构成回路 1.Kruskal算法 Kruskal算法(克鲁斯卡尔算法)任给一个有n个顶点的连通网络N{V,E} 首先构造一个由这n个顶点组成、不含任何边的图G{V,NULL}其中每个顶点自成一个连通分量 其次不断从E中取出权值最小的一条边(若有多条任取其一)若该边的两个顶点来自不同的连通分量则将此边加入到G中。如此重复直到所有顶点在同一个连通分量上为止 核心每次迭代时选出一条具有最小权值且两端点不在同一连通分量上的边加入生成树 struct Edge {size_t _srci;size_t _dsti;W _w;Edge(size_t srci, size_t dsti, const W w) :_srci(srci), _dsti(dsti), _w(w){ }bool operator(const Edge e) const{return _w e._w;} };W Kruskal(Self minTree) {size_t n _vertexs.size();minTree._vertexs _vertexs;minTree._indexMap _indexMap;minTree._matrix.resize(n);for (size_t i 0; i n; i){minTree._matrix[i].resize(n, MAX_W);}priority_queueEdge, vectorEdge, greaterEdge minque;for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (i j _matrix[i][j] ! MAX_W){minque.push(Edge(i, j, _matrix[i][j]));}}}cout Kruskal开始选边: endl;//选出n-1条边int size 0;W totalW W();UnionFindSet ufs(n);while (!minque.empty()){Edge min minque.top();minque.pop();if (!ufs.InSet(min._srci, min._dsti)){cout _vertexs[min._srci] - _vertexs[min._dsti] : min._w endl;minTree._AddEdge(min._srci, min._dsti, min._w);ufs.Union(min._srci, min._dsti);size;totalW min._w;}else{cout 构成环;cout _vertexs[min._srci] - _vertexs[min._dsti] : min._w endl;}}cout endl;if (size n - 1){return totalW;}else{return W();} }void TestGraphMinTree() {const char str[] abcdefghi;Graphchar, int g(str, strlen(str));g.AddEdge(a, b, 4);g.AddEdge(a, h, 8);g.AddEdge(a, h, 9);g.AddEdge(b, c, 8);g.AddEdge(b, h, 11);g.AddEdge(c, i, 2);g.AddEdge(c, f, 4);g.AddEdge(c, d, 7);g.AddEdge(d, f, 14);g.AddEdge(d, e, 9);g.AddEdge(e, f, 10);g.AddEdge(f, g, 2);g.AddEdge(g, h, 1);g.AddEdge(g, i, 6);g.AddEdge(h, i, 7);Graphchar, int kminTree;cout Kruskal: g.Kruskal(kminTree) endl;kminTree.Print();cout endl; } 2.Prim算法 Prim算法(普里姆算法) W Prim(Self minTree, const W src) {size_t srci GetVertexIndex(src);size_t n _vertexs.size();minTree._vertexs _vertexs;minTree._indexMap _indexMap;minTree._matrix.resize(n);for (size_t i 0; i n; i){minTree._matrix[i].resize(n, MAX_W);}vectorbool X(n, false);vectorbool Y(n, true);X[srci] true;Y[srci] false;//从X到Y集合相连接的边中选出值最小的边priority_queueEdge, vectorEdge, greaterEdge minq;//将srci连接的边添加到队列中for (size_t i 0; i n; i){if (_matrix[srci][i] ! MAX_W){minq.push(Edge(srci, i, _matrix[srci][i]));}}cout Prim开始选边: endl;int size 0;W totalW W();while (!minq.empty()){Edge min minq.top();minq.pop();if (X[min._dsti]){cout 构成环;cout _vertexs[min._srci] - _vertexs[min._dsti] : min._w endl;}else{minTree._AddEdge(min._srci, min._dsti, min._w);cout _vertexs[min._srci] - _vertexs[min._dsti] : min._w endl;X[min._dsti] true;Y[min._dsti] false;size;totalW min._w;if (size n - 1)break;for (size_t i 0; i n; i){if (_matrix[min._dsti][i] ! MAX_W Y[i]){minq.push(Edge(min._dsti, i, _matrix[min._dsti][i]));}}}}cout endl;if (size n - 1){return totalW;}else{return W();} } void TestGraphMinTree() {const char str[] abcdefghi;Graphchar, int g(str, strlen(str));g.AddEdge(a, b, 4);g.AddEdge(a, h, 8);g.AddEdge(a, h, 9);g.AddEdge(b, c, 8);g.AddEdge(b, h, 11);g.AddEdge(c, i, 2);g.AddEdge(c, f, 4);g.AddEdge(c, d, 7);g.AddEdge(d, f, 14);g.AddEdge(d, e, 9);g.AddEdge(e, f, 10);g.AddEdge(f, g, 2);g.AddEdge(g, h, 1);g.AddEdge(g, i, 6);g.AddEdge(h, i, 7);Graphchar, int pminTree;cout Prim: g.Prim(pminTree, a) endl;pminTree.Print(); }五.最短路径 最短路径问题从在带权有向图G中的某一顶点出发找出一条通往另一顶点的最短路径最短也就是沿路径各边的权值总和达到最小 1.单源最短路径--Dijkstra算法 单源最短路径问题给定一个图G ( V E ) G(VE)G(VE)求源结点s ∈ V s∈Vs∈V到图中每个结点v ∈ V v∈Vv∈V的最短路径。Dijkstra算法就适用于解决带权重的有向图上的单源最短路径问题同时算法要求图中所有边的权重非负。一般在求解最短路径的时候都是已知一个起点和一个终点所以使用Dijkstra算法求解过后也就得到了所需起点到终点的最短路径 针对一个带权有向图G将所有结点分为两组S和QS是已经确定最短路径的结点集合在初始时为空初始时就可以将源节点s放入毕竟源节点到自己的代价是0Q 为其余未确定最短路径 的结点集合每次从Q 中找出一个起点到该结点代价最小的结点u 将u 从Q 中移出并放入S中对u的每一个相邻结点v 进行松弛操作。松弛即对每一个相邻结点v 判断源节点s到结点u 的代价与u 到v 的代价之和是否比原来s 到v 的代价更小若代价比原来小则要将s 到v 的代价更新 为s 到u 与u 到v 的代价之和否则维持原样。如此一直循环直至集合Q 为空即所有节点都已经 查找过一遍并确定了最短路径至于一些起点到达不了的结点在算法循环后其代价仍为初始设定 的值不发生变化。Dijkstra算法每次都是选择V-S中最小的路径节点来进行更新并加入S中所 以该算法使用的是贪心策略 Dijkstra算法(迪杰斯特拉算法)存在的问题是不支持图中带负权路径如果带有负权路径则可能会找不到一些路径的最短路径 //时间复杂度:O(N^2),空间复杂度:O(N) void Dijkstra(const V src, vectorW dist, vectorint pPath) {size_t srci GetVertexIndex(src);size_t n _vertexs.size();dist.resize(n, MAX_W);pPath.resize(n, -1);dist[srci] 0;pPath[srci] srci;//已经确定最短路径的顶点集合vectorbool S(n, false);for (size_t j 0; j n; j){//选出最短路径顶点且不在S更新其他路径int u 0;W min MAX_W;for (size_t i 0; i n; i){if (S[i] false dist[i] min){u i;min dist[i];}}S[u] true;//松弛更新for (size_t v 0; v n; v){if (S[v] false _matrix[u][v] ! MAX_W dist[u] _matrix[u][v] dist[v]){dist[v] dist[u] _matrix[u][v];pPath[v] u;}}} } void TestGraphDijkstra() {const char* str syztx;Graphchar, int, INT_MAX, true g(str, strlen(str));g.AddEdge(s, t, 10);g.AddEdge(s, y, 5);g.AddEdge(y, t, 3);g.AddEdge(y, x, 9);g.AddEdge(y, z, 2);g.AddEdge(z, s, 7);g.AddEdge(z, x, 6);g.AddEdge(t, y, 2);g.AddEdge(t, x, 1);g.AddEdge(x, z, 4);vectorint dist;vectorint parentPath;g.Dijkstra(s, dist, parentPath);g.PrintShortPath(s, dist, parentPath); } 2.单源最短路径--Bellman-Ford算法 Dijkstra算法只能用来解决正权图的单源最短路径问题但有些题目会出现负权图。这时这个算法就不能帮助我们解决问题了而bellman—ford算法(贝尔曼-福特算法)可以解决负权图的单源最短路径问题。它的优点是可以解决有负权边的单源最短路径问题而且可以用来判断是否有负权回路。它也有明显的缺点它的时间复杂度 O(N*E) (N是点数E是边数)普遍是要高于Dijkstra算法O(N²)的。像这里 如果我们使用邻接矩阵实现那么遍历所有边的数量的时间复杂度就是O(N^3)这里也可以看出来Bellman-Ford就是一种暴力求解更新 //时间复杂度:O(N^3),空间复杂度:O(N) bool BellmanFord(const V src, vectorW dist, vectorint pPath) {size_t srci GetVertexIndex(src);size_t n _vertexs.size();// vectorW dist,记录srci-其他顶点最短路径权值数组dist.resize(n, MAX_W);// vectorint pPath 记录srci-其他顶点最短路径父顶点数组pPath.resize(n, -1);// 先更新srci-srci为最小值dist[srci] W();for (size_t k 0; k n; k){bool updata false;cout 更新第 k 轮: endl;for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (_matrix[i][j] ! MAX_W dist[i] _matrix[i][j] dist[j]){updata true;cout _vertexs[i] - _vertexs[j] : _matrix[i][j] endl;dist[j] dist[i] _matrix[i][j];pPath[j] i;}}}//如果这个轮次没有更新出最短路径,后续轮次就不需要再走if (updata false)break;}//如果还能更新就是带负权回路for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (_matrix[i][j] ! MAX_W dist[i] _matrix[i][j] dist[j]){return false;}}}return true; } void TestGraphBellmanFord() {const char* str syztx;Graphchar, int, INT_MAX, true g(str, strlen(str));g.AddEdge(s, t, 6);g.AddEdge(s, y, 7);g.AddEdge(y, z, 9);g.AddEdge(y, x, -3);//g.AddEdge(y, s, 1);//新增g.AddEdge(z, s, 2);g.AddEdge(z, x, 7);g.AddEdge(t, x, 5);g.AddEdge(t, y, 8);//g.AddEdge(t, y, -8);//更改g.AddEdge(t, z, -4);g.AddEdge(x, t, -2);vectorint dist;vectorint parentPath;if (g.BellmanFord(s, dist, parentPath)){g.PrintShortPath(s, dist, parentPath);}else{cout 存在负权回路 endl;} } 3.多源最短路径--Floyd-Warshall算法 Floyd-Warshall算法(弗洛伊德算法)是解决任意两点间的最短路径的一种算法 Floyd算法考虑的是一条最短路径的中间节点即简单路径p{v1,v2,…,vn}上除v1和vn的任意节点 设k是p的一个中间节点那么从i到j的最短路径p就被分成i到k和k到j的两段最短路径p1p2。p1 是从i到k且中间节点属于{12…k-1}取得的一条最短路径。p2是从k到j且中间节点属于{1 2…k-1}取得的一条最短路径 Floyd算法本质是三维动态规划D[i][j][k]表示从点i到点j只经过0到k个点最短路径然后建立 起转移方程然后通过空间优化优化掉最后一维度变成一个最短路径的迭代算法最后即得到所有点的最短路径 void FloydWarShall(vectorvectorW vvDist, vectorvectorint vvpPath) {size_t n _vertexs.size();vvDist.resize(n);vvpPath.resize(n);for (size_t i 0; i n; i){vvDist[i].resize(n, MAX_W);vvpPath[i].resize(n, -1);}for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (_matrix[i][j] ! MAX_W){vvDist[i][j] _matrix[i][j];vvpPath[i][j] i;}if (i j){vvDist[i][j] 0;}}}//最短路径的更新for (size_t k 0; k n; k){for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (vvDist[i][k] ! MAX_W vvDist[k][j] ! MAX_W vvDist[i][k] vvDist[k][j] vvDist[i][j]){vvDist[i][j] vvDist[i][k] vvDist[k][j];vvpPath[i][j] vvpPath[k][j];}}}} } void TestFloydWarShall() {const char* str 12345;Graphchar, int, INT_MAX, true g(str, strlen(str));g.AddEdge(1, 2, 3);g.AddEdge(1, 3, 8);g.AddEdge(1, 5, -4);g.AddEdge(2, 4, 1);g.AddEdge(2, 5, 7);g.AddEdge(3, 2, 4);g.AddEdge(4, 1, 2);g.AddEdge(4, 3, -5);g.AddEdge(5, 4, 6);vectorvectorint vvDist;vectorvectorint vvParentPath;g.FloydWarShall(vvDist, vvParentPath);// 打印任意两点之间的最短路径for (size_t i 0; i strlen(str); i){g.PrintShortPath(str[i], vvDist[i], vvParentPath[i]);cout endl;} } 六.整体实现 1.UnionFindSet.h #pragma once #includevectorclass UnionFindSet { public:UnionFindSet(size_t n) :_ufs(n, -1){ }int FindRoot(int x){int root x;while (_ufs[root] 0)root _ufs[root];//路径压缩while (_ufs[x] 0){int parent _ufs[x];_ufs[x] root;x parent;}return root;}bool Union(int x1, int x2){int root1 FindRoot(x1);int root2 FindRoot(x2);if (root1 root2)//x1和x2本来就在一个集合中return false;//数据量小的向大的合并if (abs(_ufs[root1]) abs(_ufs[root2]))swap(root1, root2);_ufs[root1] _ufs[root2];_ufs[root2] root1;return true;}bool InSet(int x1, int x2){return FindRoot(x1) FindRoot(x2);}size_t SetSize(){size_t n 0;for (auto e : _ufs){if (e 0)n;}return n;} private:vectorint _ufs; };void TestUoionFindSet() {UnionFindSet ufs(10);ufs.Union(8, 9);ufs.Union(7, 8);ufs.Union(6, 7);ufs.Union(5, 6);ufs.Union(4, 5); } 2.Graph.h #pragma once #includevector #includestring #includemap #includequeue #includeset #includefunctionalnamespace matrix {templateclass V, class W, W MAX_W INT_MAX, bool Direction falseclass Graph{typedef GraphV, W, MAX_W, Direction Self;public://图的创建//1.IO输入-不方便测试,oj中更适合//2.图结构关系写到文件,读取文件//3.手动添加边Graph() default;Graph(const V* a, size_t n){_vertexs.reserve(n);for (size_t i 0; i n; i){_vertexs.push_back(a[i]);_indexMap[a[i]] i;}_matrix.resize(n);for (size_t i 0; i _matrix.size(); i){_matrix[i].resize(n, MAX_W);}}size_t GetVertexIndex(const V v){auto it _indexMap.find(v);if (it ! _indexMap.end()){return it-second;}else{//assert(false);throw invalid_argument(顶点不存在);return -1;}}void _AddEdge(size_t srci, size_t dsti, const W w){_matrix[srci][dsti] w;//无向图if (Direction false){_matrix[dsti][srci] w;}}void AddEdge(const V src, const V dst, const W w){size_t srci GetVertexIndex(src);size_t dsti GetVertexIndex(dst);_AddEdge(srci, dsti, w);}void Print(){//顶点for (size_t i 0; i _vertexs.size(); i){cout [ i ] - _vertexs[i] endl;}cout endl;//矩阵//横下标cout ;for (size_t i 0; i _matrix.size(); i){//cout i ;printf(%4d, i);}cout endl;for (size_t i 0; i _matrix.size(); i){cout i ;//竖下标for (size_t j 0; j _matrix[i].size(); j){//cout _matrix[i][j] ;if (_matrix[i][j] MAX_W){//cout * ;printf(%4c, *);}else{//cout _matrix[i][j] ;printf(%4d, _matrix[i][j]);}}cout endl;}cout endl;}void BFS(const V src){size_t srci GetVertexIndex(src);//队列和标记数组queueint q;vectorbool visited(_vertexs.size(), false);q.push(srci);visited[srci] true;int levelSize 1;size_t n _vertexs.size();while (!q.empty()){//一层一层出for (int i 0; i levelSize; i){int front q.front();q.pop();cout front : _vertexs[front] ;//把front顶点的邻接顶点入队列for (size_t i 0; i n; i){if (_matrix[front][i] ! MAX_W){if (visited[i] false){q.push(i);visited[i] true;}}}}cout endl;levelSize q.size();}cout endl;}void _DFS(size_t srci, vectorbool visited){cout srci : _vertexs[srci] endl;visited[srci] true;//找一个和srci相邻的没有访问过的点,去深度遍历for (size_t i 0; i _vertexs.size(); i){if (_matrix[srci][i] ! MAX_W visited[i] false){_DFS(i, visited);}}}void DFS(const V src){size_t srci GetVertexIndex(src);vectorbool visited(_vertexs.size(), false);_DFS(srci, visited);}struct Edge{size_t _srci;size_t _dsti;W _w;Edge(size_t srci, size_t dsti, const W w) :_srci(srci), _dsti(dsti), _w(w){ }bool operator(const Edge e) const{return _w e._w;}};W Kruskal(Self minTree){size_t n _vertexs.size();minTree._vertexs _vertexs;minTree._indexMap _indexMap;minTree._matrix.resize(n);for (size_t i 0; i n; i){minTree._matrix[i].resize(n, MAX_W);}priority_queueEdge, vectorEdge, greaterEdge minque;for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (i j _matrix[i][j] ! MAX_W){minque.push(Edge(i, j, _matrix[i][j]));}}}cout Kruskal开始选边: endl;//选出n-1条边int size 0;W totalW W();UnionFindSet ufs(n);while (!minque.empty()){Edge min minque.top();minque.pop();if (!ufs.InSet(min._srci, min._dsti)){cout _vertexs[min._srci] - _vertexs[min._dsti] : min._w endl;minTree._AddEdge(min._srci, min._dsti, min._w);ufs.Union(min._srci, min._dsti);size;totalW min._w;}else{cout 构成环;cout _vertexs[min._srci] - _vertexs[min._dsti] : min._w endl;}}cout endl;if (size n - 1){return totalW;}else{return W();}}W Prim(Self minTree, const W src){size_t srci GetVertexIndex(src);size_t n _vertexs.size();minTree._vertexs _vertexs;minTree._indexMap _indexMap;minTree._matrix.resize(n);for (size_t i 0; i n; i){minTree._matrix[i].resize(n, MAX_W);}vectorbool X(n, false);vectorbool Y(n, true);X[srci] true;Y[srci] false;//从X到Y集合相连接的边中选出值最小的边priority_queueEdge, vectorEdge, greaterEdge minq;//将srci连接的边添加到队列中for (size_t i 0; i n; i){if (_matrix[srci][i] ! MAX_W){minq.push(Edge(srci, i, _matrix[srci][i]));}}cout Prim开始选边: endl;int size 0;W totalW W();while (!minq.empty()){Edge min minq.top();minq.pop();if (X[min._dsti]){cout 构成环;cout _vertexs[min._srci] - _vertexs[min._dsti] : min._w endl;}else{minTree._AddEdge(min._srci, min._dsti, min._w);cout _vertexs[min._srci] - _vertexs[min._dsti] : min._w endl;X[min._dsti] true;Y[min._dsti] false;size;totalW min._w;if (size n - 1)break;for (size_t i 0; i n; i){if (_matrix[min._dsti][i] ! MAX_W Y[i]){minq.push(Edge(min._dsti, i, _matrix[min._dsti][i]));}}}}cout endl;if (size n - 1){return totalW;}else{return W();}}void PrintShortPath(const V src, const vectorW dist, const vectorint pPath){size_t srci GetVertexIndex(src);size_t n _vertexs.size();for (size_t i 0; i n; i){if (i ! srci){//找出i顶点的路径vectorint path;size_t parenti i;while (parenti ! srci){path.push_back(parenti);parenti pPath[parenti];}path.push_back(srci);reverse(path.begin(), path.end());for (auto index : path){cout _vertexs[index] -;}cout 权值和: dist[i] endl;}}}//时间复杂度:O(N^2),空间复杂度:O(N)void Dijkstra(const V src, vectorW dist, vectorint pPath){size_t srci GetVertexIndex(src);size_t n _vertexs.size();dist.resize(n, MAX_W);pPath.resize(n, -1);dist[srci] 0;pPath[srci] srci;//已经确定最短路径的顶点集合vectorbool S(n, false);for (size_t j 0; j n; j){//选出最短路径顶点且不在S更新其他路径int u 0;W min MAX_W;for (size_t i 0; i n; i){if (S[i] false dist[i] min){u i;min dist[i];}}S[u] true;//松弛更新for (size_t v 0; v n; v){if (S[v] false _matrix[u][v] ! MAX_W dist[u] _matrix[u][v] dist[v]){dist[v] dist[u] _matrix[u][v];pPath[v] u;}}}}//时间复杂度:O(N^3),空间复杂度:O(N)bool BellmanFord(const V src, vectorW dist, vectorint pPath){size_t srci GetVertexIndex(src);size_t n _vertexs.size();// vectorW dist,记录srci-其他顶点最短路径权值数组dist.resize(n, MAX_W);// vectorint pPath 记录srci-其他顶点最短路径父顶点数组pPath.resize(n, -1);// 先更新srci-srci为最小值dist[srci] W();for (size_t k 0; k n; k){bool updata false;cout 更新第 k 轮: endl;for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (_matrix[i][j] ! MAX_W dist[i] _matrix[i][j] dist[j]){updata true;cout _vertexs[i] - _vertexs[j] : _matrix[i][j] endl;dist[j] dist[i] _matrix[i][j];pPath[j] i;}}}//如果这个轮次没有更新出最短路径,后续轮次就不需要再走if (updata false)break;}//如果还能更新就是带负权回路for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (_matrix[i][j] ! MAX_W dist[i] _matrix[i][j] dist[j]){return false;}}}return true;}void FloydWarShall(vectorvectorW vvDist, vectorvectorint vvpPath){size_t n _vertexs.size();vvDist.resize(n);vvpPath.resize(n);for (size_t i 0; i n; i){vvDist[i].resize(n, MAX_W);vvpPath[i].resize(n, -1);}for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (_matrix[i][j] ! MAX_W){vvDist[i][j] _matrix[i][j];vvpPath[i][j] i;}if (i j){vvDist[i][j] 0;}}}//最短路径的更新for (size_t k 0; k n; k){for (size_t i 0; i n; i){for (size_t j 0; j n; j){if (vvDist[i][k] ! MAX_W vvDist[k][j] ! MAX_W vvDist[i][k] vvDist[k][j] vvDist[i][j]){vvDist[i][j] vvDist[i][k] vvDist[k][j];vvpPath[i][j] vvpPath[k][j];}}}}}private:vectorV _vertexs; //顶点集合mapV, int _indexMap; //顶点映射下标vectorvectorW _matrix; //邻接矩阵};void TestGraph1(){Graphchar, int g(0123, 4);//Graphchar, int, true g(0123, 4);g.AddEdge(0, 1, 1);g.AddEdge(0, 3, 4);g.AddEdge(1, 3, 2);g.AddEdge(1, 2, 9);g.AddEdge(2, 3, 8);g.AddEdge(2, 1, 5);g.AddEdge(2, 0, 3);g.AddEdge(3, 2, 6);g.Print();}void TestBDFS(){string a[] { 张三, 李四, 王五, 赵六, 周七 };Graphstring, int g1(a, sizeof(a) / sizeof(string));g1.AddEdge(张三, 李四, 100);g1.AddEdge(张三, 王五, 200);g1.AddEdge(王五, 赵六, 30);g1.AddEdge(王五, 周七, 30);g1.Print();g1.BFS(张三);g1.DFS(张三);}void TestGraphMinTree(){const char str[] abcdefghi;Graphchar, int g(str, strlen(str));g.AddEdge(a, b, 4);g.AddEdge(a, h, 8);g.AddEdge(a, h, 9);g.AddEdge(b, c, 8);g.AddEdge(b, h, 11);g.AddEdge(c, i, 2);g.AddEdge(c, f, 4);g.AddEdge(c, d, 7);g.AddEdge(d, f, 14);g.AddEdge(d, e, 9);g.AddEdge(e, f, 10);g.AddEdge(f, g, 2);g.AddEdge(g, h, 1);g.AddEdge(g, i, 6);g.AddEdge(h, i, 7);Graphchar, int kminTree;cout Kruskal: g.Kruskal(kminTree) endl;kminTree.Print();cout endl;Graphchar, int pminTree;cout Prim: g.Prim(pminTree, a) endl;pminTree.Print();}void TestGraphDijkstra(){const char* str syztx;Graphchar, int, INT_MAX, true g(str, strlen(str));g.AddEdge(s, t, 10);g.AddEdge(s, y, 5);g.AddEdge(y, t, 3);g.AddEdge(y, x, 9);g.AddEdge(y, z, 2);g.AddEdge(z, s, 7);g.AddEdge(z, x, 6);g.AddEdge(t, y, 2);g.AddEdge(t, x, 1);g.AddEdge(x, z, 4);vectorint dist;vectorint parentPath;g.Dijkstra(s, dist, parentPath);g.PrintShortPath(s, dist, parentPath);}void TestGraphBellmanFord(){const char* str syztx;Graphchar, int, INT_MAX, true g(str, strlen(str));g.AddEdge(s, t, 6);g.AddEdge(s, y, 7);g.AddEdge(y, z, 9);g.AddEdge(y, x, -3);//g.AddEdge(y, s, 1);//新增g.AddEdge(z, s, 2);g.AddEdge(z, x, 7);g.AddEdge(t, x, 5);g.AddEdge(t, y, 8);//g.AddEdge(t, y, -8);//更改g.AddEdge(t, z, -4);g.AddEdge(x, t, -2);vectorint dist;vectorint parentPath;if (g.BellmanFord(s, dist, parentPath)){g.PrintShortPath(s, dist, parentPath);}else{cout 存在负权回路 endl;}}void TestFloydWarShall(){const char* str 12345;Graphchar, int, INT_MAX, true g(str, strlen(str));g.AddEdge(1, 2, 3);g.AddEdge(1, 3, 8);g.AddEdge(1, 5, -4);g.AddEdge(2, 4, 1);g.AddEdge(2, 5, 7);g.AddEdge(3, 2, 4);g.AddEdge(4, 1, 2);g.AddEdge(4, 3, -5);g.AddEdge(5, 4, 6);vectorvectorint vvDist;vectorvectorint vvParentPath;g.FloydWarShall(vvDist, vvParentPath);// 打印任意两点之间的最短路径for (size_t i 0; i strlen(str); i){g.PrintShortPath(str[i], vvDist[i], vvParentPath[i]);cout endl;}} }namespace link_table {templateclass Wstruct Edge{//int _srci;int _dsti; //目标点的下标W _w; //权值EdgeW* _next;Edge(int dsti, const W w) :_dsti(dsti), _w(w), _next(nullptr){ }};templateclass V, class W, bool Direction falseclass Graph{typedef EdgeW Edge;public:Graph(const V* a, size_t n){_vertexs.reserve(n);for (size_t i 0; i n; i){_vertexs.push_back(a[i]);_indexMap[a[i]] i;}_tables.resize(n, nullptr);}size_t GetVertexIndex(const V v){auto it _indexMap.find(v);if (it ! _indexMap.end()){return it-second;}else{//assert(false);throw invalid_argument(顶点不存在);return -1;}}void AddEdge(const V src, const V dst, const W w){size_t srci GetVertexIndex(src);size_t dsti GetVertexIndex(dst);Edge* eg new Edge(dsti, w);eg-_next _tables[srci];_tables[srci] eg;if (Direction false){Edge* eg new Edge(srci, w);eg-_next _tables[dsti];_tables[dsti] eg;}}void Print(){//顶点for (size_t i 0; i _vertexs.size(); i){cout [ i ] - _vertexs[i] endl;}cout endl;for (size_t i 0; i _tables.size(); i){cout _vertexs[i] [ i ]-;Edge* cur _tables[i];while (cur){cout [ _vertexs[cur-_dsti] : cur-_dsti : cur-_w ]-;cur cur-_next;}cout nullptr endl;}}private:vectorV _vertexs; //顶点集合mapV, int _indexMap; //顶点映射下标vectorEdge* _tables; //邻接表};void TestGraph2(){string a[] { 张三, 李四, 王五, 赵六 };//Graphstring, int, true g1(a, 4);Graphstring, int g1(a, 4);g1.AddEdge(张三, 李四, 100);g1.AddEdge(张三, 王五, 200);g1.AddEdge(王五, 赵六, 30);g1.Print();} } 3.test.cpp #includeiostream using namespace std; #includeUnionFindSet.h #includeGraph.hint main() {//TestUoionFindSet();//matrix::TestGraph1();//matrix::TestBDFS();//matrix::TestGraphMinTree();//matrix::TestGraphDijkstra();//matrix::TestGraphBellmanFord();matrix::TestFloydWarShall();//link_table::TestGraph2();return 0; }
http://www.ho-use.cn/article/10814158.html

相关文章:

  • 做企业网站 asp的cms系统哪个好网页设计网站开发需要哪些知识
  • 网站建筑设计响应式网站开发软件
  • wordpress企业网站主题网站开发过程 知乎
  • 吴中区建设局网站在手机上设计画图的软件
  • 怎么做网站的需求广告网页设计
  • 山东省建设银行网站开发一个小程序需要多久
  • 合肥网站建设价格做网站卖什么软件
  • 石家庄做网站的有哪些公司电脑编程与网站建设
  • 石家庄网站建设公司排名dedecms官网
  • 男周志做网站平面设计兼职接单
  • 网站使用网络图片做素材 侵权网站建设免费制作
  • 长沙装修网站排名wordpress模板的幻灯片
  • 新网站如何做网站优化网站 注册模块怎么做
  • 家装网站建设多少钱j建网站
  • 金华市建设监理协会网站aso优化平台有哪些
  • 久久建筑网是个什么样的网站即将发布的手机
  • 中英企业网站管理系统上海民营企业500强
  • 三亚网站开发哪家好什么是电子商务运营
  • 外贸网站商城建设潍坊网站制作多少钱
  • 购物网站模块是什么意思电商购物网站模板下载
  • 全国分类信息网站排名新闻发布会直播在哪里看
  • 网站突然打不开是什么原因wordpress版本
  • 做网站年入多少先有域名才可以做网站吗
  • 上海万户信息技术有限公司成都网站优化
  • 城乡建设网官方网站装修高端网站建设
  • vs2010做网站做美食原创视频网站
  • 动态海报网站网站建设 官网
  • 网站制作框架汽车报价软件排行榜
  • 常德建设网站制作网站设计咨询电话
  • 哪个网站可以卖自己的设计建筑人才网一砖一瓦