K短路径算法

                                          K短路径算法

 

算法背景

K 最短路径问题是最短路径问题的扩展和变形。1959 年,霍夫曼(Hoffman) 和帕夫雷(Pavley)在论文中第一次提出k 最短路径问题。 k 最短路径问题通常包括两类:有限制的k 最短路问题和无限制的K 最短路问题。 前者要求最短路径集合不含有回路,而后者对所求得的最短路径集合无限制。

算法简介

Yen's算法是Yen 在1971 年提出的以其名字命名 的Yen 算法。Yen's算法采用了递推法中的偏离路径算法思想,适用于非负权边的有向无环图结构。

算法实例:

调用K条最短路径算法,源C,目的H,K为3。B为偏离路径集合。

1.通过Dijkstra算法计算得到最短路径A^1C-E-F-H,其中,花费为5,A[1] = C-E-F-H

2.将A[1]作为迭代路径,进行第一次迭代:

(1)以部分迭代路径(即A[1])C路径中,C点为起点,将C-E路径之间的权值设为无穷大,进行一次Dijkstra,得到路径A^2-1C-D-F-H,花费为8,将A^2-1路径加入B;

(2)以部分迭代路径(即A[1])C-E路径中,E为起点,将E-F路径之间的权值设为无穷大,进行一次Dijkstra,得到路径A^2-2C-E-G-H,花费为7,将A^2-2路径加入B;

(3)以部分迭代路径(即A[1])C-E-F路径中,F为起点,将F-H路径之间的权值设为无穷大,进行一次Dijkstra,得到路径A^2-3C-E-F-G-H,花费为8,将A^2-3路径加入B;

迭代完成,B集合中有三条路径:C-D-F-HC-E-G-HC-E-F-G-H;选出花费最小的偏离路径C-E-G-HA[2] = C-E-G-H,移出B集合。

3.将A[2]作为迭代路径,进行第二次迭代:

(1)以部分迭代路径(即A[2])C路径中,C点为起点,将C-E路径之间的权值设为无穷大,进行一次Dijkstra,得到路径A^3-1C-D-F-H但B集合已存在该路径,故不存在偏移路径;

(2)以部分迭代路径(即A[2])C-E路径中,E点为起点,将E-GE-F路径之间的权值设为无穷大 (注意,这里设置两条路径的权值原因是这两条路径分别存在于A[1]和A[2]中),进行一次Dijkstra,得到路径A^3-2C-E-D-F-H,花费为8,将A^3-2加入B;

(3)以部分迭代路径(即A[2])C-E-G路径中,G点为起点,将C-H路径之间的权值设为无穷大,不存在偏移路径。

迭代完成,B集合中有三条路径:C-D-F-HC-E-F-G-HC-E-D-F-H;由于三条路径花费均为8,则根据最小节点数进行判断,选出偏离路径C-D-F-HA[3] = C-D-F-H

此时,选出了三条最短路径,分别是:

 

 A[1] = C-E-F-H

A[2] = C-E-G-H

A[3] = C-D-F-H

 

 头文件

#ifndef _GRAPH_H
#define _GRAPH_H

#include<stdio.h>
#include<stdlib.h>
#include<vector>
#include<iostream>
#include<fstream>
#include<sstream>
#include<stack>
using namespace std;

#define MAXNODE 99
#define INFINITY 9999
#define K 10

typedef int VertexType;
typedef int EdgeType;

typedef struct node{
	VertexType adjnode;
	struct node* next;
	EdgeType weight;
}EdgeNode;

typedef struct vnode{
	VertexType vertex;
	EdgeNode* firstedge;
}VertexNode;

typedef struct MatrixGraph{
	VertexType vexs[MAXNODE + 1];							//顶点表
	EdgeType edges[MAXNODE + 1][MAXNODE + 1];		//邻接矩阵,可看作边表
}MGraph;

typedef struct Pathstruct{							//用于保存一条路径,里面有每一跳的点和该路径总距离
	VertexType node[MAXNODE + 1];
	EdgeType distance ;
	int hop;
}Path;


typedef VertexNode AdjList[MAXNODE + 1];



class Graph{
public:
	Graph(string filename);
	~Graph(){};
	void FindKpath();
	void PrintOut();
	void Dijkstra(VertexType);
	Path Graph::Dijkstra(VertexType,VertexType);
	void DijkstraAll();
	void PrintShortestPath(VertexType);
	void PrintShortestPathAll(void);
	void KShortestPath(VertexType);


private:
	MGraph mgraph;
//	AdjList adjlist;
	EdgeType **dist; 
	VertexType **pre;
	Path  **Kpath[K+1];              //存储路径,起点存在node[0].node[i]就是第i跳的点

	int e,n;			//n是节点数node,e是边数edge
};


#endif

源文件

#include "graph.h"

//邻接表方式构建图
Graph::Graph(string filename){
	int j,k,w;
	
	ifstream fin(filename,ios::in);
	fin>>n;
	fin>>e;

	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= n;j++){
			mgraph.edges[i][j] = INFINITY;
		}
		mgraph.vexs[i] = i;
	}

	for(int i = 1;i <= e;i++){
		fin>>j;
		fin>>k;
		fin>>w;
		mgraph.edges[j][k] = w;
		mgraph.edges[k][j] = w;
	}
	
	dist = (EdgeType **)malloc(sizeof(EdgeType*) * n);
	pre = (VertexType **)malloc(sizeof(VertexType*) * n);
	for(int i = 1; i <= K; i++){
		Kpath[i] = (Path **)malloc(sizeof(Path) * n);
		for(int j = 1; j <= n; j++)
			Kpath[i][j] = (Path *)malloc(sizeof(Path) * n);
	}
	for( int i = 1; i <= n; i++){
		dist[i] = (EdgeType *)malloc(sizeof(EdgeType) * n);
		pre[i] = (VertexType *)malloc(sizeof(VertexType) *n);
	}
	
}


//求出V点的所有最短路径,结果保存在类的变量Kpath[1][v][i]里面,1表示第一短路径,v、i表示从v到i,
//Kpath结构里,node[i]表示第几跳的点,node[0]是自身,也就是v,另外保存了总跳数和总距离
void Graph::Dijkstra(VertexType v){
	bool s[MAXNODE];

	for(int i = 1; i <= n; i++){
		dist[v][i] = mgraph.edges[v][i];
		s[i] = 0;

		if(dist[v][i] == INFINITY)
			pre[v][i] = 0;
		else
			pre[v][i] = v;
	}

 
	s[v] = 1;
	dist[v][v] = 0;

	for( int i = 2; i <= n; i++){
		VertexType u = v;
		EdgeType tmp = INFINITY;

		for(int j = 1; j <= n; j++){
			if(!s[j] && dist[v][j] < tmp){
				tmp = dist[v][j];
				u = j;
			}
		}
		s[u] = 1;
		for(int j = 1; j <= n; j++){
			if(mgraph.edges[u][j] + dist[v][u] < dist[v][j]){
				dist[v][j] = mgraph.edges[u][j] + dist[v][u];
				pre[v][j] = u;
			}
		}
	}

	for(VertexType i = 1; i <= n; i++){
		int counthop = 0;
		EdgeType length = 0;
		VertexType j = i;
		while(pre[v][j] != 0){
			length += mgraph.edges[j][pre[v][j]];
			j = pre[v][j];
			counthop++;
		}

		Kpath[1][v][i].hop = counthop;
		Kpath[1][v][i].distance = length;
		VertexType m = i;
		while(counthop){//处理结果是路径node[1]即为第一跳,根据pre[][]把结果弄出来
			Kpath[1][v][i].node[counthop] = m;
			m = pre[v][m];
			counthop--;
		}
		Kpath[1][v][i].node[counthop] = v;
	}
}


//这个跟上面有很大重复,稍微改了下,接收两个点,返回两点之间的最短路径
Path Graph::Dijkstra(VertexType v,VertexType e){            
	bool s[MAXNODE];
	//Path *tmpath = (Path*)malloc(sizeof(Path) * n);
	Path tmpath[MAXNODE];
	Path nopath;

	nopath.distance = 0;
	nopath.hop = 0;

	int flag = 0;

	for(int i = 1; i <= n; i++){
		if(mgraph.edges[v][i] != INFINITY){
			flag = 1;
			break;
		}
	}

	if(flag == 0)
		return nopath;

	for(int i = 1; i <= n; i++){
		dist[v][i] = mgraph.edges[v][i];
		s[i] = 0;

		if(dist[v][i] == INFINITY)
			pre[v][i] = 0;
		else
			pre[v][i] = v;
	}

 
	s[v] = 1;
	dist[v][v] = 0;

	for( int i = 2; i <= n; i++){
		VertexType u = v;
		EdgeType tmp = INFINITY;

		for(int j = 1; j <= n; j++){
			if(!s[j] && dist[v][j] < tmp){
				tmp = dist[v][j];
				u = j;
			}
		}
		s[u] = 1;
		for(int j = 1; j <= n; j++){
			if(mgraph.edges[u][j] + dist[v][u] < dist[v][j]){
				dist[v][j] = mgraph.edges[u][j] + dist[v][u];
				pre[v][j] = u;
			}
		}
	}

	for(VertexType i = 1; i <= e; i++){
		int counthop = 0;
		EdgeType length = 0;
		VertexType j = i;
		while(pre[v][j] != 0){
			length += mgraph.edges[j][pre[v][j]];
			j = pre[v][j];
			counthop++;
		}

		tmpath[i].hop = counthop;
		tmpath[i].distance = length;
		VertexType m = i;
		while(counthop){								//处理结果是路径node[1]即为第一跳,不存取本节点
			tmpath[i].node[counthop] = m;
			m = pre[v][m];
			counthop--;
		}
		tmpath[i].node[counthop] = v;
	}

	Path tmpath2 = tmpath[e];
	return tmpath2;

}




void Graph::PrintShortestPath(VertexType v){
	for(VertexType i = 1; i <= n; i++){
		int counthop = Kpath[1][v][i].hop;
		cout<<v;
		for(int j = 1; j <= counthop; j++)
			cout<<"-->"<<Kpath[1][v][i].node[j];
		cout<<"\nhop: "<<counthop<<endl;
		cout<<"distance: "<<Kpath[1][v][i].distance<<endl;
		cout<<endl;
	}
}

//求出所有点之间的最短路径
void Graph::DijkstraAll(){
	for(VertexType i = 1; i <= n; i++){
		Dijkstra(i);
	}
}

void Graph::PrintShortestPathAll(){
	for(VertexType i = 1; i <= n; i++){
		PrintShortestPath(i);
		cout<<"\n"<<endl;
	}
}


void Graph::PrintOut(void){
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			if(mgraph.edges[i][j] != INFINITY && mgraph.edges[i][j] != 0)
				cout<<"<"<<i<<","<<j<<">:"<<mgraph.edges[i][j]<<endl;
		}
	}

	cout<<"Output End"<<endl;
}



void Graph::KShortestPath(VertexType v){		//求出v点到其他所有点的K最短路径,K在define里指定

	typedef struct tmpedge{
		VertexType a,b;
		EdgeType c;
	}tmpedge;

	//vector<Path> pathset;
	VertexType end = 8;
	Path sufpath;
	Path pathset[100];
	int pathcount = 0;
	stack<tmpedge> tmpstore;

	tmpedge t;

	

	for(int j = 1; j <= K - 1; j++){			//第K短路径要参考第K-1短的路径情况

	for(int i = 1; i <= Kpath[j][v][end].hop; i++){
		int flag = 0;
		t.a = Kpath[j][v][end].node[i - 1];
		t.b = Kpath[j][v][end].node[i];
		t.c = mgraph.edges[Kpath[j][v][end].node[i]][Kpath[j][v][end].node[i - 1]];
		tmpstore.push(t);
		mgraph.edges[Kpath[j][v][end].node[i - 1]][Kpath[j][v][end].node[i]] = INFINITY;
		mgraph.edges[Kpath[j][v][end].node[i]][Kpath[j][v][end].node[i - 1]] = INFINITY;		//遍历,另K-1短路径里面的每条边断一次

		sufpath = Dijkstra(Kpath[j][v][end].node[i - 1],end);                       //求出新的路径
		if(sufpath.distance == 0 && sufpath.hop == 0){						//如果路径不存在,就把原来设置为无穷的给复原
			while(!tmpstore.empty()){
				t = tmpstore.top();
				tmpstore.pop();
				mgraph.edges[t.a][t.b] = t.c;
				mgraph.edges[t.b][t.a] = t.c;
			}
			continue;
		}
		while(flag != 1){							//flag=1说明新的路径没有与之前的任何K-1条路径的前i个点重合
			for(int m = 1;m <= j; m++){                                // m <= k - 1
				int flag2 = 0;
				int count = 1;
				for( count = 1; count <= i - 1; count++){                   //flag2 = 1 表示前i-1个点不重合
					if( Kpath[m][v][end].node[count] != Kpath[j][v][end].node[count])
						flag2 = 1;
				}
				if( flag2 == 0 && Kpath[m][v][end].node[count] == sufpath.node[1])   //flag2 = 0表示前i-1个点重合。
					flag2 = 2;

				if( flag2 == 2 ){                                                 //flag2 = 2表示前i个点都重合
					flag = 0;
					t.a = Kpath[m][v][end].node[i - 1];
					t.b = Kpath[m][v][end].node[i];
					t.c = mgraph.edges[Kpath[m][v][end].node[i]][Kpath[m][v][end].node[i - 1]];                 //重合就要把边设为无穷,再求最短路径
					tmpstore.push(t);
					mgraph.edges[Kpath[m][v][end].node[i - 1]][Kpath[m][v][end].node[i]] = INFINITY;
					mgraph.edges[Kpath[m][v][end].node[i]][Kpath[m][v][end].node[i - 1]] = INFINITY;
					sufpath = Dijkstra(Kpath[m][v][end].node[i - 1],end);
					break;
				}
				else if( m == j )
					flag = 1;
			}
		}
		if(sufpath.distance == 0 && sufpath.hop == 0){                     //如果总是重合,这个情况算是结束,复原边的情况。
			while(!tmpstore.empty()){
				t = tmpstore.top();
				tmpstore.pop();
				mgraph.edges[t.a][t.b] = t.c;
				mgraph.edges[t.b][t.a] = t.c;
			}
			continue;
		}

		for(int h = sufpath.hop + i; h >= 1; h--){						//从i遍历出的路径是由两部分组成的,i之前是第K-1短路径的前i个点。后面是新求的。
			if (h >= i) 
				sufpath.node[h] = sufpath.node[h - i + 1];
			else{
				sufpath.node[h] = Kpath[j][v][end].node[h];
				sufpath.hop++;
				sufpath.distance += mgraph.edges[Kpath[j][v][end].node[h]][Kpath[j][v][end].node[h - 1]];
			}
		}
		sufpath.node[0] = v;

		while(!tmpstore.empty()){
			t = tmpstore.top();
			tmpstore.pop();
			mgraph.edges[t.a][t.b] = t.c;
			mgraph.edges[t.b][t.a] = t.c;
		}
//		pathset.push_back(sufpath);
		
		VertexType noloop[MAXNODE+1] = {0};           //监测路径中是否有环路
		int loop = 0;
		for(int f = 0; f <= sufpath.hop; f++){
			if( noloop[sufpath.node[f]] == 0)
				noloop[sufpath.node[f]] = 1;
			else
				loop = 1;
		}
		if(loop == 0)
			pathset[pathcount++] = sufpath;           //没有环路,则放入pathset中,pathset里面放了每一次求出的符合条件的路径
	}      

	int toremove = 0;
	Path spath = pathset[0];

	if( pathcount == 0){
		cout<<"\nno loopless path left\n"<<endl;
		cout<<"at most   " << j <<"   shortest paths are found"<<endl;
		
		break;
	}
	for(int i = 1; i < pathcount; i++)
		if(pathset[i].distance < spath.distance){			//在求K短时候,就是在每一次遍历后,从pathset里面选出一条。
			spath = pathset[i];								//注意K短一定要遍历K-1的所有边,但最后的结果可能不是从K-1的遍历中出来的,只要是最短就行
			toremove = i;
		}
	for(int i = 0; i <= pathcount; i++){
		if(i >= toremove ){							//pathset输出一条,就把那条删除掉
			pathset[i] = pathset[i+1];
		}
	}
	pathcount--;

	Kpath[j + 1][v][end] = spath;	
	int counthop = Kpath[j + 1][v][end].hop;
	cout<<v<<"'s  "<<j+1<<"  shortest path"<<endl;
	cout<<v;
	for(int l = 1; l <= counthop; l++)
		cout<<"-->"<<Kpath[j + 1][v][end].node[l];
	cout<<"\nhop: "<<counthop<<endl;
	cout<<"distance: "<<Kpath[j + 1][v][end].distance<<endl;
	cout<<endl;
	

	}
}



主函数

#include"graph.h"

int main(){
	Graph g("graph.txt");

	g.PrintOut();

	g.DijkstraAll();
	g.PrintShortestPathAll();
	g.KShortestPath(2);
	system("pause");
	return 0;
}

测试文件

8 11
1 2 4
1 3 5
1 4 7
2 5 5
3 4 4
3 5 6
3 6 7
4 6 4
5 8 6
6 7 5
7 8 2

C#版本

//最短路径算法结构体
    class Node
    {
        public int number;
        //value是指从0到这个节点总共要走多远,执行算法前将value的值初始化为无穷大
        public double value;
        public int parent;
    }
    /*
    // K短路径 结构体开始
    */
    class node
    {
        public int adjnode;
        public node next;
        public double weight;       // 权值
    }
    class vnode
    {
        public int vertex;
        public node firstedge;
    }
    //用于保存一条路径,里面有每一跳的点和该路径总距离
    class Path
    {
        public int[] node = new int[CommonData.Max_Node];
        public double distance;
        public int hop;
    }
    class MGraph
    {
      public  int [] vexs = new int[CommonData.Max_Node + 1];                           //顶点表
      public  double [,] edges = new double[CommonData.Max_Node + 1,CommonData.Max_Node + 1];		//邻接矩阵,可看作边表
    }

    public class tmpedge
    {
        public int a, b;
        public double c;
    }

    // K短路径 结构体结束

    //K短路径算法类开始
    class Graph
    {
        public Graph(int _n, double[,] _rec, int _K)
        {
            CommonData.Max_Node = _n + 1;
            n = _n;
            K = _K;
            mgraph = new MGraph();
            for(int i =0; i<=n;i++)
            {
                mgraph.edges[0, i] = CommonData.Max_Distance;
                mgraph.edges[i, 0] = CommonData.Max_Distance;
            }

            double[,] rec1 = new double[n + 1, n + 1];
            for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                {
                    double __num = _rec[i , j ];
                    if (_rec[i , j ] == 0)
                        rec1[i + 1, j + 1] = CommonData.Max_Distance;
                    else
                        rec1[i + 1, j + 1] = _rec[i, j];
                }
            for (int i = 1; i <= n; i++)
            {
                for (int j = 1; j <= n; j++)
                {
                    mgraph.edges[i, j] = CommonData.Max_Distance;
                    double cnn = rec1[i, j];                   
                    if (rec1[i, j] != CommonData.Max_Distance) 
                    {
                        mgraph.edges[i, j] = rec1[i, j];
                    }
                }
                mgraph.vexs[i] = i;
            }

            dist = new double[n +1, n+1];
            pre = new int[n+1, n+1];
            Kpath = new Path[K+1, n+1, n+1];

            for (int i = 0; i < K + 1; i++)
                for (int j = 0; j < n + 1; j++)
                    for (int l = 0; l < n + 1; l++)
                        Kpath[i, j, l] = new Path();

        }
        public void FindKpath()
        {
            ;
        }
        public void PrintOut()
        {
            //for (int i = 1; i <= n; i++)
            //{
            //    for (int j = 1; j <= n; j++)
            //    {
            //        if (mgraph.edges[i][j] != INFINITY && mgraph.edges[i][j] != 0)
            //            cout << "<" << i << "," << j << ">:" << mgraph.edges[i][j] << endl;
            //    }
            //}

            //cout << "Output End" << endl;
        }
        public void Dijkstra(int v)
        {
            bool[] s = new bool[CommonData.Max_Node];

            for (int i = 1; i <= n; i++)
            {
                dist[v,i] = mgraph.edges[v,i];
                s[i] = false;

                if (dist[v,i] == CommonData.Max_Distance)
                    pre[v,i] = 0;
                else
                    pre[v,i] = v;
            }


            s[v] = true;
            dist[v,v] = 0;

            for (int i = 2; i <= n; i++)
            {
                int u = v;
                double tmp = CommonData.Max_Distance;

                for (int j = 1; j <= n; j++)
                {
                    if (!s[j] && dist[v,j] < tmp)
                    {
                        tmp = dist[v,j];
                        u = j;
                    }
                }
                s[u] = true;
                for (int j = 1; j <= n; j++)
                {
                    if (mgraph.edges[u,j] + dist[v,u] < dist[v,j])
                    {
                        dist[v,j] = mgraph.edges[u,j] + dist[v,u];
                        pre[v,j] = u;
                    }
                }
            }

            for (int i = 1; i <= n; i++)
            {
                int counthop = 0;
                double length = 0;
                int j = i;
                int num = pre[v, j];
                while (pre[v,j] != 0)
                {
                    length += mgraph.edges[j,pre[v,j]];
                    j = pre[v,j];
                    counthop++;
                }

                Kpath[1,v,i].hop = counthop;
                Kpath[1,v,i].distance = length;
                int m = i;
                while (counthop > 0)
                {                               //处理结果是路径node[1]即为第一跳,根据pre[][]把结果弄出来
                    Kpath[1,v,i].node[counthop] = m;
                    m = pre[v,m];
                    counthop--;
                }
                Kpath[1,v,i].node[counthop] = v;
            }
        }
        public Path Dijkstra(int v, int e)
        {
            bool [] s = new bool[CommonData.Max_Node];
            //Path *tmpath = (Path*)malloc(sizeof(Path) * n);
            Path [] tmpath = new Path[CommonData.Max_Node];

            for(int i=0; i< CommonData.Max_Node;i++)
            {
                tmpath[i] = new Path();
            }
            Path nopath = new Path();

            nopath.distance = 0;
            nopath.hop = 0;

            int flag = 0;

            for (int i = 1; i <= n; i++)
            {
                if (mgraph.edges[v,i] != CommonData.Max_Distance)
                {
                    flag = 1;
                    break;
                }
            }

            if (flag == 0)
                return nopath;

            for (int i = 1; i <= n; i++)
            {
                dist[v,i] = mgraph.edges[v,i];
                s[i] = false;

                if (dist[v,i] == CommonData.Max_Distance)
                    pre[v,i] = 0;
                else
                    pre[v,i] = v;
            }


            s[v] = true;
            dist[v,v] = 0;

            for (int i = 2; i <= n; i++)
            {
                int u = v;
                double tmp = CommonData.Max_Distance;

                for (int j = 1; j <= n; j++)
                {
                    if (!s[j] && dist[v,j] < tmp)
                    {
                        tmp = dist[v,j];
                        u = j;
                    }
                }
                s[u] = true;
                for (int j = 1; j <= n; j++)
                {
                    if (mgraph.edges[u,j] + dist[v,u] < dist[v,j])
                    {
                        dist[v,j] = mgraph.edges[u,j] + dist[v,u];
                        pre[v,j] = u;
                    }
                }
            }

            for (int i = 1; i <= e; i++)
            {
                int counthop = 0;
                double length = 0;
                int j = i;
                while (pre[v,j] != 0)
                {
                    length += mgraph.edges[j,pre[v,j]];
                    j = pre[v,j];
                    counthop++;
                }

                tmpath[i].hop = counthop;
                tmpath[i].distance = length;
                int m = i;
                while (counthop > 0)
                {                               //处理结果是路径node[1]即为第一跳,不存取本节点
                    tmpath[i].node[counthop] = m;
                    m = pre[v,m];
                    counthop--;
                }
                tmpath[i].node[counthop] = v;
            }

            Path tmpath2 = tmpath[e];
            return tmpath2;
        }
        public void DijkstraAll()
        {
            for (int i = 1; i <= n; i++)
            {
                Dijkstra(i);
            }
        }
        public void PrintShortestPath(int _i)
        {
            //for (VertexType i = 1; i <= n; i++)
            //{
            //    int counthop = Kpath[1][v][i].hop;
            //    cout << v;
            //    for (int j = 1; j <= counthop; j++)
            //        cout << "-->" << Kpath[1][v][i].node[j];
            //    cout << "\nhop: " << counthop << endl;
            //    cout << "distance: " << Kpath[1][v][i].distance << endl;
            //    cout << endl;
            //}
        }
        public void PrintShortestPathAll(object o)
        {
            //for (int i = 1; i <= n; i++)
            //{
            //    PrintShortestPath(i);
            //    cout << "\n" << endl;
            //}
        }
        public List<int> KShortestPath(int v)
        {
            int end = n;
            Path sufpath = new Path();
            Path[] pathset = new Path[100];
            int pathcount = 0;
            Stack<tmpedge> tmpstore = new Stack<tmpedge>();

            tmpedge t = new tmpedge();
            for (int j = 1; j <= K - 1; j++)    //第K短路径要参考第K-1短的路径情况
            {
                for (int i = 1; i <= Kpath[j,v,end].hop; i++)
                {
                    int flag = 0;
                    t.a = Kpath[j,v,end].node[i-1];
                    t.b = Kpath[j,v,end].node[i];
                    t.c = mgraph.edges[Kpath[j,v,end].node[i],Kpath[j,v,end].node[i - 1]];
                    tmpstore.Push(t);
                    mgraph.edges[Kpath[j,v,end].node[i - 1],Kpath[j,v,end].node[i]] = CommonData.Max_Distance;
                    mgraph.edges[Kpath[j,v,end].node[i],Kpath[j,v,end].node[i - 1]] = CommonData.Max_Distance;		//遍历,另K-1短路径里面的每条边断一次
                    sufpath = Dijkstra(Kpath[j,v,end].node[i - 1], end);                       //求出新的路径
                    if (sufpath.distance == 0 && sufpath.hop == 0)                       //如果路径不存在,就把原来设置为无穷的给复原
                    {
                        while (tmpstore.Count > 0)
                        {
                            t = tmpstore.Peek();
                            tmpstore.Pop();
                            mgraph.edges[t.a,t.b] = t.c;
                            mgraph.edges[t.b,t.a] = t.c;
                        }
                        continue;
                    }
                    while (flag != 1)
                    {                           //flag=1说明新的路径没有与之前的任何K-1条路径的前i个点重合
                        for (int m = 1; m <= j; m++)
                        {                                // m <= k - 1
                            int flag2 = 0;
                            int count = 1;
                            for (count = 1; count <= i - 1; count++)
                            {                   //flag2 = 1 表示前i-1个点不重合
                                if (Kpath[m,v,end].node[count] != Kpath[j,v,end].node[count])
                                    flag2 = 1;
                            }
                            if (flag2 == 0 && Kpath[m,v,end].node[count] == sufpath.node[1])   //flag2 = 0表示前i-1个点重合。
                                flag2 = 2;

                            if (flag2 == 2)
                            {                                                 //flag2 = 2表示前i个点都重合
                                flag = 0;
                                t.a = Kpath[m,v,end].node[i - 1];
                                t.b = Kpath[m,v,end].node[i];
                                t.c = mgraph.edges[Kpath[m,v,end].node[i],Kpath[m,v,end].node[i - 1]];                 //重合就要把边设为无穷,再求最短路径
                                tmpstore.Push(t);
                                mgraph.edges[Kpath[m,v,end].node[i - 1],Kpath[m,v,end].node[i]] = CommonData.Max_Distance;
                                mgraph.edges[Kpath[m,v,end].node[i],Kpath[m,v,end].node[i - 1]] = CommonData.Max_Distance;
                                sufpath = Dijkstra(Kpath[m,v,end].node[i - 1], end);
                                break;
                            }
                            else if (m == j)
                                flag = 1;
                        }
                    }
                    if (sufpath.distance == 0 && sufpath.hop == 0)     //如果总是重合,这个情况算是结束,复原边的情况。
                    {                     
                        while (tmpstore.Count > 0)
                        {
                            t = tmpstore.Peek();
                            tmpstore.Pop();
                            mgraph.edges[t.a,t.b] = t.c;
                            mgraph.edges[t.b,t.a] = t.c;
                        }
                        continue;
                    }  
                    for (int h = sufpath.hop + i; h >= 1; h--)     //从i遍历出的路径是由两部分组成的,i之前是第K-1短路径的前i个点。后面是新求的。
                    {                      
                        if (h >= i)
                            sufpath.node[h] = sufpath.node[h - i + 1];
                        else
                        {
                            sufpath.node[h] = Kpath[j,v,end].node[h];
                            sufpath.hop++;
                            sufpath.distance += mgraph.edges[Kpath[j,v,end].node[h],Kpath[j,v,end].node[h - 1]];
                        }
                    }
                    sufpath.node[0] = v;
                    while (tmpstore.Count > 0)
                    {
                        t = tmpstore.Peek();
                        tmpstore.Pop();
                        mgraph.edges[t.a,t.b] = t.c;
                        mgraph.edges[t.b,t.a] = t.c;
                    }
                    int [] noloop = new int[CommonData.Max_Node + 1];           //监测路径中是否有环路
                    int loop = 0;
                    for (int f = 0; f <= sufpath.hop; f++)
                    {
                        if (noloop[sufpath.node[f]] == 0)
                            noloop[sufpath.node[f]] = 1;
                        else
                            loop = 1;
                    }
                    if (loop == 0)
                        pathset[pathcount++] = sufpath;           //没有环路,则放入pathset中,pathset里面放了每一次求出的符合条件的路径
                    int toremove = 0;
                    Path spath = pathset[0];
                    if (pathcount == 0)
                    {
                        break;
                    }
                    for (int i1 = 1; i1 < pathcount; i1++)
                        if (pathset[i1].distance < spath.distance)    //在求K短时候,就是在每一次遍历后,从pathset里面选出一条。
                        {          
                            spath = pathset[i1];                             //注意K短一定要遍历K-1的所有边,但最后的结果可能不是从K-1的遍历中出来的,只要是最短就行
                            toremove = i1;
                        }
                    for (int i1 = 0; i1 <= pathcount; i1++)
                    {
                        if (i1 >= toremove)            //pathset输出一条,就把那条删除掉
                        {                           
                            pathset[i1] = pathset[i1 + 1];
                        }
                    }
                    pathcount--;
                    Kpath[j + 1,v,end] = spath;                    

                }
            }
            int counthop = Kpath[K, v, end].hop;
            List<int> _ipath = new List<int>();
            for (int l = 1; l <= counthop; l++)
                _ipath.Add(Kpath[K,v,end].node[l]);

            return _ipath;
        }

	   private MGraph mgraph;
        //	AdjList adjlist;
       private double [,] dist;    // 距离矩阵
       private int [,] pre;
       private Path[,,] Kpath;     //存储路径,起点存在node[0].node[i]就是第i跳的点

       private int n,K;           //n是节点数node
    }

 


本公众号分享自己从程序员小白到经历春招秋招斩获10几个offer的面试笔试经验,其中包括【Java】、【操作系统】、【计算机网络】、【设计模式】、【数据结构与算法】、【大厂面经】、【数据库】期待你加入!!!

1.计算机网络----三次握手四次挥手
2.梦想成真-----项目自我介绍
3.你们要的设计模式来了
4.一字一句教你面试“个人简介”
5.30场面试分享接近
 

  • 9
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haikuotiankongdong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值