12.带权有向图中任意两点间的最短路径

其实它的代码理解起来真的挺难的我觉得!!!

昨天看了一下午感觉晦涩难懂,还是matlab好用,直接调用函数就可以了!!!

不过这里还是得跟大家介绍一下:

1.问题的理解:

像这种带权的有向图,每一行都表示该行标号对应列标号的有向权值,本身到本身的数值为0,没办法到达的数值为∞

2.最优子结构

i,j是图里面的两个不同顶点,设p为从i到j的不经过{k+1,k+2,...n}点的最短路径

(1)若p不经过顶点k,则p也是从i到达j其间不经过{k,k+1,k+2...n}的最短路径

(2)若p经过顶点k,我们把前半段从i到k记为p1,后半段从k到j记做p2,则p1是从i到k不经过{k,k+1,...n}的最短路径,p2是从k到j的其间不经过{k,k+1,k+2...n}的最短路径

算法伪代码:

扫描二维码关注公众号,回复: 3493936 查看本文章

FLOYD-WARSHALL(w)

1.    for i<-1 to n

2.      do for j<-1 to n

3.        do if i=j or w[i,j]=∞

4.          then π[i,j]<-NIL

5.          else π[i,j]<-i

6.    D<-w

7.    for k<-1 to n

8.      do for i<- 1 to n

9.        do for j<-1 to n

10.        if D[i,j]>D[i,k]+D[k,j]

11.           then D[i,j]<-D[i,k]+D[k,j]

12.                   π[i,j]<-π[k,j]

13.    return D,π

(吐槽一下,这里的D其实就是每行标号到每列标号的最短距离,后期程序出来后还是很漂亮的,然后这里的π我就不知道什么鬼了,索性就不管他啦,哈哈!!)

PRINT-ALL-PAIRS-SHORTEST -PATHS(π,i,j)

1.    if i=j

2.      then print i

3.      else if π[i,j]=NIL

4.             then print"no path from " i “to” j "exists"

5.              else PRINT-ALL-PAIRS-SHORTEST-PATHS(π,i,π[i,j])

6.                      print j

C++:

floyd.h

#define _floyd_h
#include<string.h>
#include<float.h>
#include<stdio.h>
#include"pair.h"
#include<malloc.h>
pair floydwarshall(double* w,int n){
    double *d=(double*)malloc(n*n*sizeof(double));
    int i,j,k,*pi=(int*)malloc(n*n*sizeof(int));
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            if(j==i||w[i*n+j]>=DBL_MAX)
                pi[i*n+j]=-1;
            else
                pi[i*n+j]=i;
    memcpy(d,w,n*n*sizeof(double));
    for(k=1;k<=n;k++)
        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
                if(d[i*n+j]>d[i*n+k-1]+d[(k-1)*n+j]){
                d[i*n+j]=d[i*n+k-1]+d[(k-1)*n+j];
                pi[i*n+j]=pi[(k-1)*n+j];
                }
                return make_pair(d,pi);
}
void printallpairsshotestpath(int *pi,int n,int i,int j){
    if(i==j){
    printf("%d ",i+1);
    return;
    }
    if(pi[i*n+j]==-1)
        printf("no path from %d to %d exists.\n",i+1,j+1);
    else{
    printallpairsshotestpath(pi,n,i,pi[i*n+j]);
    printf("%d ",j+1);
    }
}

main.cpp

#include<stdlib.h>
#include"floyd.h"
int main(){
    double w[]={0,3,8,DBL_MAX,-4,
                DBL_MAX,0,DBL_MAX,1,7,
                DBL_MAX,4,0,DBL_MAX,DBL_MAX,
                2,DBL_MAX,-5,0,DBL_MAX,
                DBL_MAX,DBL_MAX,DBL_MAX,6,0},*d;
    int i,j,k,*pi,n=5;
    pair r;
    r=floydwarshall(w,n);
    d=(double*)r.first;
    pi=(int*)r.second;
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
        printallpairsshotestpath(pi,n,i,j);
        printf(":%1.1f\n",d[i*n+j]);
        }
    }
    free(d);
    free(pi);
}

输出结果:

JAVA:

Floyd.java

package Jamin;
import java.util.Arrays;
public class Floyd {
public static Pair floydwarshall(double[][] w) {
    int n=w.length,i,j,k;
    double[][] d=new double[n][n];
    int[][] pi=new int[n][n];
    d=Arrays.copyOf(w,n);
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            if(j==i||w[i][j]>=Double.MAX_VALUE)
                pi[i][j]=-1;
            else
                pi[i][j]=i;
    for(k=1;k<=n;k++)
        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
                if(d[i][j]>d[i][k-1]+d[k-1][j]) {
                    d[i][j]=d[i][k-1]+d[k-1][j];
                    pi[i][j]=pi[k-1][j];
                }
    return Pair.make(d, pi);
}
public static void printallpairsshotestpath(int[][] pi,int i,int j) {
    int n=pi.length;
    if(i==j) {
        System.out.print((i+1)+" ");
        return;
    }
    if(pi[i][j]==-1) 
        System.out.println("no path from " +(i+1)+"to "+(j+1)+"exists.");
        else {
            printallpairsshotestpath(pi,i,pi[i][j]);
            System.out.print((j+1)+" ");
        }
    }
}

Test.java

package Jamin;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
double[][] w= {{0.0,3.0,8.0,Double.MAX_VALUE,-4.0},
        {Double.MAX_VALUE,0.0,Double.MAX_VALUE,1.0,7.0},
        {Double.MAX_VALUE,4.0,0.0,Double.MAX_VALUE,Double.MAX_VALUE},
        {2.0,Double.MAX_VALUE,-5.0,0.0,Double.MAX_VALUE},
        {Double.MAX_VALUE,Double.MAX_VALUE,Double.MAX_VALUE,6.0,0.0}
},d;
int n=5,i,j,k;
int[][] pi;
Pair r;
r=Floyd.floydwarshall(w);
d=(double[][])r.first;
pi=(int[][])r.second;
for(i=0;i<n;i++) {
    for(j=0;j<n;j++) {
        Floyd.printallpairsshotestpath(pi, i, j);
        System.out.println(":"+d[i][j]);
    }
}
}
}
输出结果跟上面一样的!

JAVA:(贪心算法版)

探讨本部分时可以参考下该链接:

https://blog.csdn.net/weixin_39653545/article/details/82925768

贪心选择:

由图中内容可知,其贪心选择方式跟最小生成树是一样的:

从第一个起始点开始(生成树的根),遍历剩下的位置点,找到在根附近的点中距离最小的位置点,记录下来放在位置点集合U中,然后在剩下的点中遍历找到位置点集合U中所有位置点的附近点,找到距离最短的,记录下来放在集合U中,重复多次直至所有的点都在集合U中。

Shortestpath.java

package Jamin;
import java.util.Arrays;
public class Shortestpath {
public static Pair dijkstra(double[][] w,int s) {
    int n=w.length,i;
    Vertex[] d=new Vertex[n];
    int[] pi=new int[n];
    boolean[] poped=new boolean[n];
    Arrays.fill(pi,-1);
    Arrays.fill(poped,false);
    for(i=0;i<n;i++)
        d[i]=new Vertex(Double.POSITIVE_INFINITY,i);
    d[s].weight=0.0;
    Prioqueue Q=new Prioqueue(new Less());
    for(i=0;i<n;i++)
        Q.enqueue(d[i]);
    while(!Q.empty()) {
        int u=((Vertex)(Q.dequeue())).index;
        poped[u]=true;
        for(int v=0;v<n;v++) {
            if(w[u][v]>0.0)
                if(!poped[v])
                    if(d[v].weight>d[u].weight+w[u][v]) {
                        pi[v]=u;
                        d[v].weight=d[u].weight+w[u][v];
                    }
        }
        Q.fix();
    }
    return Pair.make(d, pi);
}
public static void printpath(int[] pi,int s,int i) {
    if(i==s) {
        System.out.print((i+1)+" ");
        return;
    }
    if(pi[i]==-1)
        System.out.println("no path form "+(s+1)+"to"+(i+1));
    else {
        printpath(pi,s,pi[i]);
        System.out.print((i+1)+" ");
    }
}
}
 

Test.java

package Jamin;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
Pair r=new Pair();
double a[][]= {{0,10,0,5,0},
        {0,0,1,2,0},
        {0,0,0,0,4},
        {0,3,9,0,2},
        {7,0,6,0,0}};//这里的矩阵表示:第一个为标号1到标号1的距离,第一行第二个为标号1到标号2的距离。。。
int i,n=5,s=0;//这里的n表示有5个标号位置
int[] pi;
Vertex[] d;
r=Shortestpath.dijkstra(a, s);
d=(Vertex[])r.first;
pi=(int[])r.second;
for(i=0;i<n;i++) {
    if(i!=s) {
        Shortestpath.printpath(pi, s, i);
        System.out.println();
        System.out.println(d[i].weight);
    }
}
}
}
 

输出结果:

1 4 2    //行走路径
8.0      //总距离
1 4 2 3 
9.0
1 4 
5.0
1 4 5 
7.0
 

猜你喜欢

转载自blog.csdn.net/weixin_39653545/article/details/82905172
今日推荐