反圈法解决最短路径问题
2015-01-17 15:02
330 查看
反圈发求最短路径算法介绍:
Java实现代码:
Java实现代码:
package sy3; /* * 构造图的边结构 */ public class Arc { public Vnode firstNode;//定义边的始点 public Vnode LastNode;//定义边的中点 public Arc NextArc;//定义边的下一条边 public boolean flag;//标识边是否访问过 public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public Arc getNextArc() { return NextArc; } public void setNextArc(Arc nextArc) { NextArc = nextArc; } public Vnode getLastNode() { return LastNode; } public void setLastNode(Vnode lastNode) { LastNode = lastNode; } public int weight;//定义边对应的权值 //建立一条具有权值weight的边 public Arc(int weight){ this(null,null,null,weight); } public Arc(Vnode firstNode,Vnode LastNode,int weight){ this(firstNode,LastNode,null,weight); } public Arc(Vnode firstNode,Vnode LastNode,Arc NextArc,int weight){ this.firstNode=firstNode; this.LastNode=LastNode; this.NextArc=NextArc; this.weight=weight; } public Vnode getFirstNode() { return firstNode; } public void setFirstNode(Vnode firstNode) { this.firstNode = firstNode; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } }
package sy3; public enum GraphKind { Gra,//无向图 Digra,//有向图 FlowGra;//网络流图 }
package sy3; /* * 新建一个图结构接口 */ public interface IGraph { public void createGraph() throws Exception;//新建图 public int getVexNum();//返回图中顶点数 public int getArcNum();//返回图中边数 public String getVex(int v) throws Exception;//给定顶点v所处的位置,返回顶点对应顶点名称 public int locateVex(String v) throws Exception;//给定顶点名称,返回对应顶点的位置 public int firstAdjVex(int v) throws Exception;//给定顶点所处位置,返回该顶点的第一个邻接点 public int nextAdjVex(int v,int w) throws Exception;//给定顶点v以及它的邻接点w对应的位置,返回顶点相对于w的下一个邻接点的位置 }
package sy3; import java.util.Scanner; /* * 构造图结构 */ public class MyGraph implements IGraph { public final static int Inf=Integer.MAX_VALUE;//表示整型无穷大,用来标识两个顶点是否有边相连 public GraphKind kind;//定义图的类型 public int vexNum,arcNum;//定义顶点以及边的数目 public int vw[];//顶点位置集 public Vnode[] V;//顶点结构 public Arc[] A;//边结构 public String[] v;//顶点名称集 public int[][] arcs;//邻接矩阵也就是边的关系 public int[][][] F;//网络流图构成的邻接矩阵 public void createGraph() throws Exception { Scanner s=new Scanner(System.in); System.out.println("请输入所要构建的图的类型:"); GraphKind kind=GraphKind.valueOf(s.next()); //开关语句选择构图方法 switch(kind){ case Gra: createGra();//构造无向图 return; case Digra: createDigra();//构造有向图 return; case FlowGra: createFlow();//构造有向图 return; } } /* * 构造网络流图 */ private void createFlow() throws Exception { Scanner s=new Scanner(System.in); System.out.println("请分别输入图的顶点数和边数;"); vexNum=s.nextInt();//输入顶点数 arcNum=s.nextInt();//输入边数 v=new String[vexNum]; vw=new int[vexNum]; V=new Vnode[vexNum]; for(int i=0;i<vexNum;i++){ V[i]=new Vnode(v[i],vw[i]);//定义顶点集 } System.out.println("请分别输入图的各个顶点:"); for(int i=0;i<vexNum;i++){ String S=s.next(); int vw=s.nextInt(); V[i].setV(S); V[i].setVw(vw); } //初始化邻接矩阵 F=new int[vexNum][vexNum][3]; for(int i=0;i<vexNum;i++){ for(int j=0;j<vexNum;j++){ F[i][j][0]=0;//初始化容量值 F[i][j][1]=0;//初始化流量值 F[i][j][2]=Inf;//初始化费用值,表示不存在这条弧 } } System.out.println("请输入每条边的两个顶点及其相关参数:"); for(int i=0;i<arcNum;i++){ int v=locateVex(s.next());//输入起始点 int u=locateVex(s.next());//输入终点 for(int j=0;j<3;j++){ F[v][u][j]=s.nextInt(); } } } /* * 构造有向图 */ private void createDigra() throws Exception { Scanner s=new Scanner(System.in); System.out.println("请分别输入图的顶点数和边数;"); vexNum=s.nextInt();//输入顶点数 arcNum=s.nextInt();//输入边数 v=new String[vexNum]; vw=new int[vexNum]; V=new Vnode[vexNum]; A=new Arc[arcNum]; for(int i=0;i<vexNum;i++){ V[i]=new Vnode(v[i],vw[i]);//定义顶点集 } System.out.println("请分别输入图的各个顶点:"); for(int i=0;i<vexNum;i++){ String S=s.next(); int vw=s.nextInt(); V[i].setV(S); V[i].setVw(vw); } //初始化邻接矩阵 arcs=new int[vexNum][vexNum]; for(int i=0;i<vexNum;i++){ for(int j=0;j<vexNum;j++){ arcs[i][j]=Inf; } } System.out.println("请输入每条边的两个顶点及其权值:"); for(int i=0;i<arcNum;i++){ int v=locateVex(s.next());//输入起始点 int u=locateVex(s.next());//输入终点 arcs[v][u]=s.nextInt();//输入顶点v到顶点u的弧的权重值 A[i]=new Arc(V[v],V[u],arcs[v][u]); } } /* * 构造无向图 */ private void createGra() throws Exception { Scanner s=new Scanner(System.in); System.out.println("请分别输入图的顶点数和边数;"); vexNum=s.nextInt();//输入顶点数 arcNum=s.nextInt();//输入边数 v=new String[vexNum]; vw=new int[vexNum]; V=new Vnode[vexNum]; for(int i=0;i<vexNum;i++){ V[i]=new Vnode(v[i],vw[i]);//定义顶点集 } System.out.println("请分别输入图的各个顶点:"); for(int i=0;i<vexNum;i++){ String S=s.next(); int vw=s.nextInt(); V[i].setV(S); V[i].setVw(vw); } //初始化邻接矩阵 arcs=new int[vexNum][vexNum]; for(int i=0;i<vexNum;i++){ for(int j=0;j<vexNum;j++){ arcs[i][j]=Inf; } } System.out.println("请输入每条边的两个顶点及其权值:"); for(int i=0;i<arcNum;i++){ int v=locateVex(s.next());//输入起始点 int u=locateVex(s.next());//输入终点 arcs[v][u]=arcs[u][v]=s.nextInt();//输入顶点v到顶点u的弧的权重值 } } public int getVexNum() { return vexNum; } public int getArcNum() { return arcNum; } //如果已知顶点在邻接矩阵中的位置,返回顶点的名称 public String getVex(int v) throws Exception{ if(v<0 || v>vexNum){ throw new Exception("第"+v+"个顶点不存在"); } return V[v].getV(); } //判断所给的顶点名称是否是图中的顶点,如果是则返回顶点所在的位置 public int locateVex(String v) throws Exception { for(int i=0;i<vexNum;i++){ //System.out.println(v); if(getVex(i).equals(v)){ //System.out.println(i); return i; } } return -1; } //返回v位置顶点的下一个邻接点的位置 public int firstAdjVex(int v) throws Exception { if(v<0 || v>vexNum){ throw new Exception("第"+v+"个顶点不存在"); } for(int i=0;i<vexNum;i++){ if(arcs[v][i]!=-1 && arcs[v][i]<Inf){ return i; } } return -1; } //已知始点和终点的位置,返回该边在边集合A中的下标 public int FirstIndex(int a,int b){ for(int i=0;i<arcNum;i++){ if(A[i].getFirstNode().getVw()==a && A[i].getLastNode().getVw()==b){ return i; } } return -1; } //返回v位置顶点的下一个邻接点的位置(即查找v的下一个邻接点) public int nextAdjVex(int v, int w) throws Exception { if(v<0 || v>=vexNum){ throw new Exception("第"+v+"个顶点不存在!"); }// if Vnode vex=V[v];//找到位置v上的顶点 Arc arcvw=null;//初始化一条边 for(Arc arc=vex.getAw()[0];arc!=null;arc=arc.NextArc){ if(arc.getFirstNode().getVw()==w){ arcvw=arc; break; }// if }// for if(arcvw!=null && arcvw.getNextArc()!=null){ return arcvw.getNextArc().getFirstNode().getVw(); } else return -1; } public static void main(String args[]) throws Exception{ int n=0,m=0; MyGraph G=new MyGraph(); G.createGraph(); System.out.println("请输出所构建图的邻接矩阵:"); for(int i=-1;i<G.getVexNum();i++){ if(i<0){ System.out.print(" "); for(int j=0;j<G.getVexNum();j++){ System.out.print(G.getVex(j)+" "); } System.out.println(); }else{ for(int j=-1;j<G.getVexNum();j++){ if(j<0){ System.out.print(G.getVex(i)+" "); } else{ if(G.arcs[i][j]==Inf){ System.out.print("INF"+" "); }// if else{ System.out.print(G.arcs[i][j]+" "); }//else }// else }// for System.out.println(); }// else }// if } }
package sy3; /* * 建立一个图中的顶点结构 */ public class Vnode { public int vw;//顶点的序数(即表示第几个顶点) public String V;//顶点的名称 public boolean flag;//标识顶点是否访问过 public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public String getV() { return V; } public void setV(String v) { V = v; } public int getVw() { return vw; } public void setVw(int vw) { this.vw = vw; } public Arc aw[];//表明从顶点出发的边的权重集 public Vnode next[];//从顶点出发的边的终点 public Vnode[] getNext() { return next; } public Arc[] getAw() { return aw; } public void setNext(Vnode next[]) { this.next = next; } public Vnode(String V,int vw,Arc aw[],Vnode next[],boolean flag){ this.vw=vw; this.next=next; this.aw=aw; this.V=V; this.flag=flag; } //返回顶点位置 public Vnode(String V,int vw){ this(V,vw,null,null,false); } }
package sy3; /* * 构造路径长度路径结构 */ public class lengthOfPath { int lamda;//路径长度 String recent;//本路径中当下顶点的前一个顶点 String past; //初始化路径 public lengthOfPath(String v){ this.lamda=0; this.recent=v; this.past=null; } public int getLamda() { return lamda; } public void setLamda(int lamda) { this.lamda = lamda; } public String getRecent() { return recent; } public void setRecent(String recent) { this.recent = recent; } public String getPast() { return past; } public void setPast(String past) { this.past = past; } }
package sy3; /* * 定义网络流图的边结构 */ public class FlowArc { public Vnode firstNode;//定义边的始点 public Vnode LastNode;//定义边的中点 public Arc NextArc;//定义边的下一条边 public int flow;//定义边的流量值 public int Capacity;//定义边的容量值 public int cost;//定义边的费用值 //构造函数 public FlowArc(Vnode u,Vnode v,Arc s,int c,int f,int b){ this.firstNode=u; this.LastNode=v; this.NextArc=s; this.flow=f; this.Capacity=c; this.cost=b; } //始点 public Vnode getFirstNode() { return firstNode; } public void setFirstNode(Vnode firstNode) { this.firstNode = firstNode; } //终点 public Vnode getLastNode() { return LastNode; } public void setLastNode(Vnode lastNode) { LastNode = lastNode; } //邻接边 public Arc getNextArc() { return NextArc; } public void setNextArc(Arc nextArc) { NextArc = nextArc; } //流量 public int getFlow() { return flow; } public void setFlow(int flow) { this.flow = flow; } //容量 public int getCapacity() { return Capacity; } public void setCapacity(int capacity) { Capacity = capacity; } //费用 public int getCost() { return cost; } public void setCost(int cost) { this.cost = cost; } }
package sy3; import java.util.Scanner; /* * 利用反圈法实现最短路径算法 */ public class ShortestPath { public final static int Inf=Integer.MAX_VALUE;//表示整型无穷大,用来标识两个顶点是否有边相连 public int[][] M;//有向图邻接矩阵 public Vnode[] V;//有向图的顶点集 public Vnode X[];//反圈中的顶点集 public Arc F[];//反圈中的边集合 public String Vs;//路径起始点 public String Vt;//路径终止点 public int ArcNum; public int num;//反圈中的边数 lengthOfPath L[];//始点到对应位置顶点的路径长度 public boolean Flag=true; public int SL=0;; //构造方法 public ShortestPath(int M[][],Vnode V[],int ArcNum){ this.M=M; this.V=V; this.ArcNum=ArcNum; X=new Vnode[V.length]; F=new Arc[ArcNum]; for(int i=0;i<ArcNum;i++){ F[i]=new Arc(null,null,Inf); } L=new lengthOfPath[X.length]; } /* * 最短路径实现方法 */ public String ShortPath(String Vs,String Vt){ int num=0; int k=0; this.Vs=Vs; this.Vt=Vt; String st=""; String S[]=new String[X.length]; //初始化S for(int i=0;i<S.length;i++){ S[i]=""; } for(int i=0;i<ArcNum;i++){ F[i]=new Arc(Inf); } S[k]=Vt; k++; for(int i=0;i<X.length;i++){ X[i]=new Vnode("",i); //System.out.println(V[i].getV()+"空"); L[i]=new lengthOfPath(X[i].getV()); } for(int i=0;i<V.length;i++){ V[i].setFlag(false); //System.out.println(Vs+V[i].getV()); if(Vs.equals(V[i].getV())){ X[i].setV(V[i].getV()); //对反圈的顶点集进行初始化 // System.out.println(X[i].getV()); V[i].setFlag(true);//表示V[i]点已经被访问过 L[i]=new lengthOfPath(Vs); L[i].setPast(null);//初始化Vs的前一个顶点的名称为null L[i].setLamda(0);//初始化Vs-->Vs的路径长度为0 } if(Vt.equals(V[i].getV())){ num=i; //S[i]=Vt; } } boolean f1=ZX(Vt); if(f1==true){ Flag=false; return ""; } else{ String temp=L[num].getRecent();//得到终点的名称 SL=L[num].getLamda(); while(!temp.equals(Vs) && k<X.length){ for(int i=0;i<X.length;i++){ if(temp.equals(X[i].getV())){ num=i; } } temp=L[num].getPast(); S[k]=temp; k++; } k=0; for(int i=S.length-1;i>0;i--){ if(!S[i].equals("")){ st=st+S[i]+"---->"; } } st=st+S[0]; return st; } } /* * 构造正向反圈的方法 */ public boolean ZX(String Vt){ boolean f=false;//用来判断是否有路 boolean flag=false;//用来判断反圈中的顶点集是否等于图的顶点集 boolean flag1=true;//用来判断反圈是否为空 int min=Inf;//用来求取最小权值弧长 int index1=0;//用来表示权值最小的非反圈对应点的位置 int index2=0;//用来表示权值最小的反圈对应点的位置 //如果反圈中顶点集不等于图的顶点集,就继续反圈运算 /* for(int i=0;i<X.length;i++){ if(X[i].getV().equals(Vt)){ flag=false; break; } }*/ while(flag==false){ flag1=true; min=Inf; for(int i=0;i<X.length;i++){ if(!X[i].getV().equals("")){ for(int j=0;j<V.length;j++){ if(V[j].isFlag()==false && M[X[i].getVw()][V[j].getVw()]!=Inf){ if((L[i].lamda+M[X[i].getVw()][V[j].getVw()])<min){ min=M[X[i].getVw()][V[j].getVw()]+L[i].lamda; index1=j; index2=i; //System.out.println(index2+" "+index1); }// if }// if }// for }// if }// for if(index1!=-1 && index2!=-1){ X[index1]=new Vnode(V[index1].getV(),index1);//将该点加入反圈的点集合 V[index1].setFlag(true); L[index1]=new lengthOfPath(X[index1].getV()); L[index1].setPast(X[index2].getV());//设置当前顶点的前一个顶点 //System.out.println(X[index1].getV()+" "+L[index1].getPast()+" "+index1); L[index1].setLamda(L[index2].getLamda()+M[index2][index1]);//计算路径长度 F[num]= new Arc(X[index2],V[index1],M[index2][index1]); } index1=-1; index2=-1; for(int i=0;i<F.length;i++){ if(F[i].getWeight()!=Inf){ flag1=false;//表示反圈中已有元素,即不为空 //System.out.println(flag1+" "+Inf+" "+F[i].getWeight()); break; } } for(int i=0;i<F.length;i++){ F[i]= new Arc(null,null,Inf); //System.out.println(F[num].getWeight()); } for(int i=0;i<X.length;i++){ if(X[i].getV().equals(Vt)){ flag=true; break; } } //System.out.println(flag+" "+flag1); if(flag1==true){ f=true; break; } }// while return f; } public static void main(String args[]) throws Exception{ //实现最短路径 String L; String vs; String vt; Scanner s=new Scanner(System.in); MyGraph G=new MyGraph(); G.createGraph(); System.out.println("请输出所构建图的邻接矩阵:"); for(int i=-1;i<G.getVexNum();i++){ if(i<0){ System.out.print(" "); for(int j=0;j<G.getVexNum();j++){ System.out.print(G.getVex(j)+" "); } System.out.println(); }else{ for(int j=-1;j<G.getVexNum();j++){ if(j<0){ System.out.print(G.getVex(i)+" "); } else{ if(G.arcs[i][j]==Inf){ System.out.print("INF"+" "); } else{ System.out.print(G.arcs[i][j]+" "); } }//else }// if System.out.println(); }// for }//else ShortestPath S=new ShortestPath(G.arcs,G.V,G.getArcNum()); System.out.println("请输入初始点:"); vs=s.next(); System.out.println("请输入终点:"); vt=s.next(); System.out.println("请输出所求的最短路径:"); L=S.ShortPath(vs, vt); if(!L.equals("")){ System.out.println(L); } System.out.println("这条最短路径的长度: "+S.SL); } }
相关文章推荐
- 用lingo解决“最短路径问题”
- Floyd算法解决最短路径问题
- Dijkstra-解决最短路径问题
- 队列优化并使用邻接表存储的Bellman-Ford算法模板解决最短路径存在负权边问题
- Bellman - Ford 算法解决最短路径问题
- (阶段三 dijkstra算法温习1.2)HDU 2066 一个人的旅行(使用dijkstra来解决多源起点和多源终点的最短路径问题)
- Java解决算法-最短路径问题
- Dijkstra算法,Bellman-Ford算法和BFS算法解决有向图的单源最短路径问题
- 图的最短路径 Ford算法 解决负权问题
- 数据结构-顺序队列解决最短迷宫路径问题
- RouteTask执行最短路径计算时“无法完成 操作”问题分析解决
- Bellman—Ford算法实现(解决存在负边情况下单源最短路径问题)
- 广度优先算法解决无向无权图的最短路径问题
- 我是怎么使用最短路径算法解决动态联动问题的
- 图的应用---最短路径问题 用迪杰斯特拉算法解决 《地铁换乘问题》
- 用栈解决迷宫问题(输出所有路径和最短路径)
- 应用拓扑排序来解决DAG(directed acylic graph)的单源最短路径问题
- 贪心算法解决单源最短路径问题
- Dijkstra算法解决最短路径问题
- 模板_Bellman-frod算法(最短路径解决负权路问题)