# 图的实现、无向图的最小生成树、有向图的最短路径

graph.h

#ifndef __GRAPH__
#define __GRAPH__

#include <iostream>
#include <queue>
using namespace std;

class DisjointSet;

template <class TypeOfEdge>
class Graph {
public:
virtual bool insert(int u, int v, TypeOfEdge weight) = 0;
virtual bool remove(int u, int v) = 0;
virtual bool modify(int u, int v, TypeOfEdge weight) = 0;
virtual bool exist(int u, int v) const = 0;
virtual int numOfVer() const {return vers;}
virtual int numOfEdge() const {return edges;}

protected:
int vers;
int edges;
};

//有向加权图的邻接表实现
//作为无权图使用时，可将weight置1，权值一样
//作为无向图使用时，插入和删除时需将两个方向的边均插入或删除，修改weight时同样
template <class TypeOfVer, class TypeOfEdge>
public:
//这里为了方便，所有成员函数写成内联函数的形式

//构造一个只有结点没有边的图
AdjListGraph(int v, const TypeOfVer *d, bool isWeightedFlag, bool isDirectedFlag){
vers = v;
edges = 0;
isWeighted = isWeightedFlag;
isDirected = isDirectedFlag;

verList = new VerNode[vers];
for (int i = 0; i < vers; ++i) {
verList[i].ver = d[i];
}
}

for (int i = 0; i < vers; ++i) {
EdgeNode *p, *pre;
while (p != NULL){
pre = p;
p = p->next;
delete pre;
}
}

delete [] verList;
}

bool insert(int u, int v, TypeOfEdge weight = 0) {
if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
return false;

if (exist(u, v))
return false;

if (!isDirected)
++edges;

return true;
}

bool remove(int u, int v) {
bool flag = removeCore(u, v);
if (!isDirected)
flag &= removeCore(v, u);
return flag;
}

bool removeCore(int u, int v) {
if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
return false;

if (p == NULL){
return false;
}
//删除结点为头结点
if (p->end == v){
delete p;
--edges;
return true;
}

//找到删除结点或找不到
EdgeNode *pre = p;
p = p->next;
while (p != NULL && p->end != v) {
pre = p;
p = p->next;
}
//找不到
if (p == NULL){
return false;
}
//找到
pre->next = p->next;
delete p;
--edges;

return true;
}

bool modify(int u, int v, TypeOfEdge weight) {
bool flag = modifyCore(u, v, weight);
if (!isDirected)
flag &= modifyCore(v, u, weight);
return flag;
}

bool modifyCore(int u, int v, TypeOfEdge weight) {
while (p != NULL && p->end != v) {
p = p->next;
}
if (p == NULL) {
return false;
}
p->weight = weight;
return true;
}

bool exist(int u, int v) const {
while (p != NULL && p->end != v) {
p = p->next;
}
if (p == NULL) {
return false;
}
return true;
}

//深度优先遍历
void dfs(int startVer = 0) const {
bool *visited = new bool[vers];
for (int i = 0; i < vers; ++i)
visited[i] = false;

int j = 0;
for (int i = startVer; i < vers + startVer; ++i){
j = i % vers;
if (visited[j])
continue;
dfsCore(j, visited);
cout << endl; //每一行为一棵深度优先生成树
}
}

//广度优先遍历
void bfs(int startVer = 0) const {
bool *visited = new bool[vers];
for (int i = 0; i < vers; ++i)
visited[i] = false;

queue<int> q;
int j = 0;
for (int i = startVer; i < vers + startVer; ++i){
j = i % vers;
if (visited[j])
continue;
q.push(j);
while (!q.empty()) {
//访问当前结点
int v = q.front();
q.pop();
if (visited[v])
continue;
cout << verList[v].ver << '\t';
visited[v] = true;

//当前结点的后继结点放入队列
while (p != NULL) {
if (!visited[p->end]) {
q.push(p->end);
}
p = p->next;
}
}
cout << endl; //每一行为一棵广度优先生成树
}
}

//欧拉回路
void eulerCircuit(TypeOfVer start) {
if (edges == 0)
return;

for (int i = 0; i < vers; ++i) {
int degree = 0;
while (p != NULL) {
++degree;
p = p->next;
}
//度数为0或奇数，不存在欧拉回路
if ((degree == 0) || (degree & 0x1))
return;
}

//找到起始点序号
int iStart = 0;
for (iStart = 0; iStart < vers; ++iStart){
if (verList[iStart].ver == start)
break;
}
if (iStart == vers)
return;

//保存一个备份
VerNode *tmp = clone();

//找到第一条路径(起点所有的边已被访问)
EulerNode *beg, *end;
eulerCircuitCore(iStart, beg, end);

EulerNode *p, *pre;
while (true) {
pre = beg;
p = beg->next;
while (p != NULL) {
break;
pre = p;
p = p->next;
}
if (p == NULL)
break;

//从某一个未访问的边开始找一条路径
EulerNode *begTmp, *endTmp;
eulerCircuitCore(p->nodeNum, begTmp, endTmp);
pre->next = begTmp;
endTmp->next = p->next;
delete p;
}

//恢复原图
delete [] verList;
verList = tmp;

p = beg;
while (p != NULL) {
cout << verList[p->nodeNum].ver << '\t';
pre = p;
p = p->next;
delete pre;
}
cout << endl;
}

//拓扑排序
void topologySort() const {
//计算入度
int *inDegree = new int[vers];
memset(inDegree, 0, vers * sizeof(int));
for (int i = 0; i < vers; ++i){
while (p != NULL) {
++inDegree[p->end];
p = p->next;
}
}

//入度为0的放入队列
queue<int> q;
for (int i = 0; i < vers; ++i){
if (inDegree[i] == 0)
q.push(i);
}

while (!q.empty()) {
int v = q.front();
q.pop();
cout << verList[v].ver << '\t';

//入度减1, 为0的放入队列
while (p != NULL) {
--inDegree[p->end];
if (inDegree[p->end] == 0) {
q.push(p->end);
}
p = p->next;
}
}
cout << endl;
}

//kruskal算法求最小生成树( 时间复杂度O(|E|log|E|) )
void kruskal() const {
priority_queue<Edge, deque<Edge>, greater<Edge>> pq;  //最小堆
//priority_queue<Edge, deque<Edge>, compEdgeGreater> pq;  //最小堆
//priority_queue<Edge> pq;  //默认最大堆
DisjointSet ds(vers);

//所有边放入优先级队列
for (int i = 0; i < vers; ++i) {
while (p != NULL) {
if (i < p->end) { //只添加一次
Edge edge(i, p->end, p->weight);
pq.push(edge);
}
p = p->next;
}
}

//合并生成最小生成树
int count = 0;
while (count < vers - 1) {
Edge edge = pq.top();
pq.pop();
int u = ds.find(edge.beg);
int v = ds.find(edge.end);
if (u != v) {
++count;
ds.unionTwoSet(u, v);
cout << "(" << verList[edge.beg].ver << "," << verList[edge.end].ver << ")\t";
}
}
cout << endl;
}

//prim算法求最小生成树( 时间复杂度O(|V^2|) )
void prim(TypeOfEdge noEdge) const {
//顶点集合V, 最小生成树结点集合U, 剩余结点V-U
bool *flag = new bool[vers];                //结点在U中为true
TypeOfEdge *lowCost = new TypeOfEdge[vers]; //U中结点到结点i的最小权值, 当i在U中时lowCost为noEdge, 当i在V-U中时lowCost为有限值
int *startNode = new int[vers];             //U中结点startNode[i]到结点i的权值是lowCost[i]

for (int i = 0; i < vers; ++i) {
flag[i] = false;
lowCost[i] = noEdge;
}

int start = 0;  //起始点
int current = start;  //current是即将加入到U中的结点
for (int i = 1; i < vers; ++i) {
while (p != NULL) {
if (!flag[p->end] && p->weight < lowCost[p->end]) { //结点p->end不在U中, 并且结点p->end到结点current的距离小于结点p->end到U中已有点的最小距离
lowCost[p->end] = p->weight;
startNode[p->end] = current;
}
p = p->next;
}

//current加入U
flag[current] = true;

//寻找V-U中到V-U的最小距离点
TypeOfEdge min = noEdge;
bool tflag = false;
for (int j = 0; j < vers; ++j) {
if (lowCost[j] < min) {
min = lowCost[j];
#if 1
current = j;  //取V-U中到U的最小距离点作为下一个计算点
#else
if (!tflag) {
tflag = true;
current = j;  //在V-U中随意取一个点，与上面的方法结果一致
}
#endif
}
}
cout << "(" << verList[startNode[current]].ver << "," << verList[current].ver << ")\t";

lowCost[current] = noEdge;
}
cout << endl;

delete [] flag;
delete [] lowCost;
delete [] startNode;
}

//非加权图的单源最短路径( bfs算法, 时间复杂度为|V|和|E|中的较小者, 即O(|V| + |E|) )
void unweightedShortDistance(TypeOfVer start, TypeOfEdge noEdge) const {
//找到起始点序号
int iStart = 0;
for (iStart = 0; iStart < vers; ++iStart) {
if (verList[iStart].ver == start)
break;
}
if (iStart == vers)
return;

TypeOfEdge *distance = new TypeOfEdge[vers];
int *prev = new int[vers];
for (int i = 0; i < vers; ++i) {
distance[i] = noEdge;
}

distance[iStart] = 0;
prev[iStart] = iStart;
queue<int> q;
q.push(iStart);
while (!q.empty()) {
int u = q.front();
q.pop();
while (p != NULL) {
if (distance[p->end] == noEdge) {
distance[p->end] = distance[u] + 1;
prev[p->end] = u;
q.push(p->end);
}
p = p->next;
}
}

for (int i = 0; i < vers; ++i) {
cout << "the path from " << start << " to "  << verList[i].ver << ": ";
printPath(iStart, i, prev);
cout << endl;
}
cout << endl;

delete [] distance;
delete [] prev;
}

//加权图的单源最短路径(dijkstra算法与prim算法有些类似, 时间复杂度O(|V^2|) )
void dijkstra(TypeOfVer start, TypeOfEdge noEdge) const {
//找到起始点序号
int iStart = 0;
for (iStart = 0; iStart < vers; ++iStart) {
if (verList[iStart].ver == start)
break;
}
if (iStart == vers)
return;

//顶点集合V, 已经找到最短路径的顶点集合U, 剩余结点V-U
TypeOfEdge *distance = new TypeOfEdge[vers];  //结点i到起始点的最短距离
bool *konwn = new bool[vers];                 //结点在U中为true
int *prev = new int[vers];                    //结点i的前继结点
for (int i = 0; i < vers; ++i) {
distance[i] = noEdge;
konwn[i] = false;
}

distance[iStart] = 0;
prev[iStart] = iStart;
int current = iStart;
for (int i = 1; i < vers; ++i) {
//寻找V-U中到U中的最小距离点
TypeOfEdge min = noEdge;
for (int j = 0; j < vers; ++j) {
if (!konwn[j] && distance[j] < min) {
min = distance[j];
current = j;
}
}

konwn[current] = true;
while (p != NULL) {
if (!konwn[p->end] && min + p->weight < distance[p->end]) {
distance[p->end] = min + p->weight;
prev[p->end] = current;
}
p = p->next;
}
}

for (int i = 0; i < vers; ++i) {
cout << "the path from " << start << " to "  << verList[i].ver << ": ";
printPath(iStart, i, prev);
cout << "\twith length: " << distance[i] << endl;
}
cout << endl;

delete [] distance;
delete [] prev;
delete [] konwn;
}

//带负权值图的单源最短路径(可以有环, 但不能有负环, 时间复杂度O(|V||E|) )
void weightedNegative(TypeOfVer start, TypeOfEdge noEdge) const {
//找到起始点序号
int iStart = 0;
for (iStart = 0; iStart < vers; ++iStart) {
if (verList[iStart].ver == start)
break;
}
if (iStart == vers)
return;

TypeOfEdge *distance = new TypeOfEdge[vers];
int *prev = new int[vers];
for (int i = 0; i < vers; ++i) {
distance[i] = noEdge;
}

distance[iStart] = 0;
prev[iStart] = iStart;
queue<int> q;
q.push(iStart);
while (!q.empty()) {
int u = q.front();
q.pop();
while (p != NULL) {
if (distance[u] + p->weight < distance[p->end]) {
distance[p->end] = distance[u] + p->weight;
prev[p->end] = u;
q.push(p->end);
}
p = p->next;
}
}

for (int i = 0; i < vers; ++i) {
cout << "the path from " << start << " to "  << verList[i].ver << ": ";
printPath(iStart, i, prev);
cout << "\twith length: " << distance[i] << endl;
}
cout << endl;

delete [] distance;
delete [] prev;
}

private:
struct EdgeNode {
int end;
TypeOfEdge weight;
EdgeNode *next;

EdgeNode(int e, TypeOfEdge w, EdgeNode *n = NULL):end(e), weight(w), next(n) {}
};

struct VerNode {
TypeOfVer ver;

VerNode(TypeOfVer v, EdgeNode *h = NULL):ver(v), head(h){}
};

VerNode *verList;
bool isWeighted;
bool isDirected;

void dfsCore(int start, bool *visited) const {
cout << verList[start].ver << '\t';
visited[start] = true;

while (p != NULL) {
if (!visited[p->end])
dfsCore(p->end, visited);
p = p->next;
}
}

struct EulerNode {
int nodeNum;
EulerNode *next;

EulerNode(int num, EulerNode *n = NULL):nodeNum(num), next(n) {}
};

VerNode *clone() const {
VerNode *tmp = new VerNode[vers];
for (int i = 0; i < vers; ++i){
tmp[i].ver = verList[i].ver;
while (p != NULL) {
p = p->next;
}
}
return tmp;
}

void eulerCircuitCore(int start, EulerNode *&beg, EulerNode *&end) {
beg = end = new EulerNode(start);
remove(start, nextNodeNum);
//remove(nextNodeNum, start);

end->next = new EulerNode(nextNodeNum);
end = end->next;

start = nextNodeNum;
}
}

struct Edge {
int beg, end;
TypeOfEdge weight;

Edge(int b, int e, TypeOfEdge w):beg(b), end(e),weight(w) {}
bool operator>(const Edge &right) const {
return weight > right.weight;
}
};

struct compEdgeGreater {
bool operator()(Edge first, Edge second) {
return first.weight > second.weight;
}
};

void printPath(int start, int end, int *prev) const {
if (start == end) {
cout << verList[start].ver;
return;
}
printPath(start, prev[end], prev);
cout << "-" << verList[end].ver;
}
};

//有向加权图的邻接矩阵实现
//作为无权图使用时，可将weight置1，权值一样
//作为无向图使用时，插入和删除时需将两个方向的边均插入或删除，修改weight时同样
template <class TypeOfVer, class TypeOfEdge>
public:
//这里为了方便，所有成员函数写成内联函数的形式
AdjMatrixGraph(int v, const TypeOfVer *d, TypeOfEdge noEdgeFlag, bool isWeightedFlag, bool isDirectedFlag) {
vers = v;
edges = 0;
noEdge = noEdgeFlag;
isWeighted = isWeightedFlag;
isDirected = isDirectedFlag;

ver = new TypeOfVer[vers];
for (int i = 0; i < vers; ++i) {
ver[i] = d[i];
}

edge = new TypeOfEdge *[vers];
for (int i = 0; i < vers; ++i) {
edge[i] = new TypeOfEdge[vers];
for (int j = 0; j < vers; ++j) {
edge[i][j] = noEdge;
}
edge[i][i] = 0;
}
}

delete [] ver;
for (int i = 0; i < vers; ++i) {
delete [] edge[i];
}
delete [] edge;
}

bool insert(int u, int v, TypeOfEdge w) {
if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
return false;
if (exist(u, v))
return false;
edge[u][v] = w;
if (!isDirected)
edge[v][u] = w;
++edges;
return true;
}

bool remove(int u, int v) {
if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
return false;
if (!exist(u, v))
return false;
edge[u][v] = noEdge;
if (!isDirected)
edge[v][u] = noEdge;
--edges;
return true;
}

bool modify(int u, int v, TypeOfEdge w) {
if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
return false;
if (!exist(u, v))
return false;
edge[u][v] = w;
if (!isDirected)
edge[v][u] = w;
return true;
}

bool exist(int u, int v) const {
if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
return false;
if (edge[u][v] == noEdge)
return false;
return true;
}

//所有顶点对的最短路径( 时间复杂度O(|V^3|) )
void floyd() const {
TypeOfEdge **d = new TypeOfEdge *[vers];
int **prev = new int *[vers];
for (int i = 0; i < vers; ++i) {
d[i] = new TypeOfEdge[vers];
prev[i] = new int[vers];
for (int j = 0; j < vers; ++j) {
d[i][j] = edge[i][j];
prev[i][j] = (edge[i][j] != noEdge) ? i : -1;
}
}

for (int k = 0; k < vers; ++k) {
for (int i = 0; i < vers; ++i) {
for (int j = 0; j < vers; ++j) {
if (d[i][k] + d[k][j] < d[i][j]) {
d[i][j] = d[i][k] + d[k][j];
prev[i][j] = prev[k][j];
}
}
}
}

for (int i = 0; i < vers; ++i) {
for (int j = 0; j < vers; ++j) {
cout << "the path from " << ver[i] << " to " << ver[j] << ": ";
printPath(i, j, prev);
cout << "\twith length: " << d[i][j]<< endl;
}
}
//cout << "最短路径" << endl;
//for (int i = 0; i < vers; ++i) {
//  for (int j = 0; j < vers; ++j) {
//    cout << prev[i][j] << "\t";
//  }
//  cout << endl;
//}
//cout << "长度" << endl;
//for (int i = 0; i < vers; ++i) {
//  for (int j = 0; j < vers; ++j) {
//    cout << d[i][j] << "\t";
//  }
//  cout << endl;
//}
cout << endl;

delete [] d;
delete [] prev;
}

private:
TypeOfEdge **edge;
TypeOfVer *ver;
TypeOfEdge noEdge;
bool isWeighted;
bool isDirected;

void printPath(int start, int end, int **prev) const {
if (start == end) {
cout << ver[start];
return;
}
printPath(start, prev[start][end], prev);
cout << "-" << ver[end];
}
};

//不相交集(并查集)
class DisjointSet {
public:
DisjointSet(int n) {
size = n;
parent = new int[n];
for (int i = 0; i < n; ++i) {
parent[i] = -1;
}
}

~DisjointSet(){
delete [] parent;
}

int find(int x) {
if (parent[x] < 0)
return x;
return parent[x] = find(parent[x]);
}

void unionTwoSet(int root1, int root2){
if (root1 == root2)
return;
if (parent[root1] > parent[root2]) {  //root1规模小
parent[root2] += parent[root1];
parent[root1] = root2;
}
else{
parent[root1] += parent[root2];
parent[root2] = root1;
}
}

private:
int size;
int *parent;
};

#endif

main.cpp

#include "graph.h"
#include <iostream>
using namespace std;

int main() {
//有向图的遍历
cout << "有向图的遍历:" << endl;
AdjListGraph<char, int> g(7, "0123456", true, true);
//adjListGraph<char, int> g(7, "1234567", true, true);
//adjListGraph<char, int> g(7, "abcdefg", true, true);
g.insert(4, 5, 1);
g.insert(4, 6, 1);
g.insert(6, 5, 1);
g.insert(5, 1, 1);
g.insert(6, 3, 1);
g.insert(1, 3, 1);
g.insert(0, 1, 1);
g.insert(3, 2, 1);
g.insert(1, 2, 1);
g.insert(3, 0, 1);
g.insert(2, 0, 1);
g.dfs();
cout << endl;
g.dfs(4);
cout << endl;
g.bfs();
cout << endl;
g.bfs(4);
cout << endl;

//无向图的欧拉回路
cout << "无向图的欧拉回路:" << endl;
AdjListGraph<char, int> eulerGraph(6, "012345", true, false);
eulerGraph.insert(0, 1, 1);
eulerGraph.insert(0, 2, 1);
eulerGraph.insert(1, 2, 1);
eulerGraph.insert(2, 3, 1);
eulerGraph.insert(1, 4, 1);
eulerGraph.insert(1, 3, 1);
eulerGraph.insert(2, 4, 1);
eulerGraph.insert(3, 4, 1);
eulerGraph.insert(3, 5, 1);
eulerGraph.insert(4, 5, 1);
eulerGraph.eulerCircuit('5');

//有向无环图的拓扑排序
cout << "有向无环图的拓扑排序:" << endl;
AdjListGraph<char, int> topologyGraph(7, "0123456", true, true);
topologyGraph.insert(0, 1, 1);
topologyGraph.insert(0, 2, 1);
topologyGraph.insert(1, 3, 1);
topologyGraph.insert(1, 4, 1);
topologyGraph.insert(1, 5, 1);
topologyGraph.insert(2, 4, 1);
topologyGraph.insert(2, 6, 1);
topologyGraph.insert(4, 5, 1);
topologyGraph.insert(4, 6, 1);
topologyGraph.insert(5, 3, 1);
topologyGraph.topologySort();

//无向图的最小生成树
cout << "最小生成树:" << endl;
//AdjListGraph<char, int> minimumSpanningTree(6, "012345", true, false);
AdjListGraph<char, int> minimumSpanningTree(6, "123456", true, false);
minimumSpanningTree.insert(0, 3, 5);
minimumSpanningTree.insert(3, 5, 2);
minimumSpanningTree.insert(4, 5, 6);
minimumSpanningTree.insert(1, 4, 3);
minimumSpanningTree.insert(0, 1, 6);
minimumSpanningTree.insert(0, 2, 1);
minimumSpanningTree.insert(1, 2, 5);
minimumSpanningTree.insert(2, 3, 5);
minimumSpanningTree.insert(2, 4, 6);
minimumSpanningTree.insert(2, 5, 4);
minimumSpanningTree.kruskal();
minimumSpanningTree.prim(INT_MAX);

//有向图的单源最短路径
cout << "单源最短路径:" << endl;
AdjListGraph<char, int> singleSourceShortestPath(7, "0123456", true, true);
singleSourceShortestPath.insert(0, 1, 2);
singleSourceShortestPath.insert(1, 4, 10);
singleSourceShortestPath.insert(4, 6, 6);
singleSourceShortestPath.insert(6, 5, 1);
singleSourceShortestPath.insert(2, 0, 4);
singleSourceShortestPath.insert(2, 5, 5);
singleSourceShortestPath.insert(0, 3, 1);
singleSourceShortestPath.insert(1, 3, 3);
singleSourceShortestPath.insert(3, 2, 2);
singleSourceShortestPath.insert(3, 4, 2);
singleSourceShortestPath.insert(3, 5, 8);
singleSourceShortestPath.insert(3, 6, 4);
cout << "非加权图" << endl;
singleSourceShortestPath.unweightedShortDistance('2', INT_MAX);
cout << "加权图" << endl;
//singleSourceShortestPath.dijkstra('1', INT_MAX);
singleSourceShortestPath.dijkstra('2', INT_MAX);

//有向带负权值图的单源最短路径
AdjListGraph<char, int> singleSourceShortestPathWeightedNegative(7, "0123456", true, true);
singleSourceShortestPathWeightedNegative.insert(0, 1, 2);
singleSourceShortestPathWeightedNegative.insert(1, 4, 10);
singleSourceShortestPathWeightedNegative.insert(4, 6, 6);
singleSourceShortestPathWeightedNegative.insert(6, 5, 1);
singleSourceShortestPathWeightedNegative.insert(2, 0, 4);
singleSourceShortestPathWeightedNegative.insert(2, 5, 3);
singleSourceShortestPathWeightedNegative.insert(0, 3, 1);
singleSourceShortestPathWeightedNegative.insert(1, 3, 3);
singleSourceShortestPathWeightedNegative.insert(3, 2, 2);
singleSourceShortestPathWeightedNegative.insert(3, 4, 2);
singleSourceShortestPathWeightedNegative.insert(3, 5, -8);
singleSourceShortestPathWeightedNegative.insert(3, 6, 4);
cout << "带负权值图" << endl;
singleSourceShortestPathWeightedNegative.weightedNegative('2', INT_MAX);

//有向图所有顶点对的最短路径
cout << "所有顶点对的最短路径:" << endl;
AdjMatrixGraph<char, int> allVertexPairShortestPath(3, "012", INT_MAX, true, true);
allVertexPairShortestPath.insert(0, 1, 8);
allVertexPairShortestPath.insert(1, 0, 3);
allVertexPairShortestPath.insert(0, 2, 5);
allVertexPairShortestPath.insert(2, 0, 6);
allVertexPairShortestPath.insert(2, 1, 2);
allVertexPairShortestPath.floyd();

int ttt = 0;
return 0;
}