您的位置:首页 > 其它

反圈法解决最短路径问题

2015-01-17 15:02 330 查看
反圈发求最短路径算法介绍:



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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: