最短路径算法

来源:互联网 发布:华为办公网络 编辑:程序博客网 时间:2024/06/07 05:56

1 Dijkstra算法

(1)确定S集与V集;
(2)找到V集中权值最小的一个Pk,并将其从V集中移入S集;
(3)以Pk为中间点,更新V集中的所有权值;
(4)重复(2)(3);结束条件为V集为空
缺陷:对于有向图和带负权的图就没有用了。

#include <stdio.h>#define NODE_COUNT  6struct Node{#define VSET    0#define SSET    1    int type;    int weight;}all[NODE_COUNT];#define INF     0xfffffffint maps[NODE_COUNT][NODE_COUNT] = {    { 0, 7, 9, INF, INF, 14 },    { 7, 0, 10, 15, INF, INF },    { 9, 10, 0, 11, INF, 2 },    { INF, 15, 11, 0, 6, INF },    { INF, INF, INF, 6, 0, 9 },    { 14, INF, 2, INF, 9, 0 }};void initset(int src){    int i = 0;    for (i = 0; i < NODE_COUNT; i++){        all[i].type = VSET;        all[i].weight = maps[src][i];    }}int getvmin(void){    int i = 0, min = INF,sel = -1;    for (i = 0; i < NODE_COUNT; i++){        if (all[i].type == VSET){            if (min > all[i].weight){                min = all[i].weight;                sel = i;            }        }    }    return sel;}int dijkstra(int src){    int sel = 0,i;    // (1) 初始化S集V集,刚开始我们将所有集合定位V集    initset(src);    // (2) 找到V集中权值最小的一个Pk    // (4) 判断V集中是否为空    while ((sel=getvmin()) != -1)    {        // (2) 将选择的Pk移入S集中        all[sel].type = SSET;        // (3) 以Pk为中间点,更新V集中的所有权值        for (i = 0; i < NODE_COUNT; i++){            if (all[i].type == VSET && maps[sel][i] != INF){                if (all[sel].weight + maps[sel][i] < all[i].weight)                    all[i].weight = all[sel].weight + maps[sel][i];            }        }    }}void main(void){    int i = 0;    dijkstra(0);    for (i = 0; i < NODE_COUNT; i++)        printf("%d:::%d\n",i,all[i].weight);}

2 Floyd算法

起始点为i,终止点为j,中间点为k,顶点格式N;

i,j,k(0,N1)

(1)确定一个中间点k
(2)更新所有i->j的权值
可用于计算有向图和带负权的图

#include <stdio.h>#define NODE_COUNT  6#define INF 0xffffffint maps[NODE_COUNT][NODE_COUNT] = {    { 0, 7, 9, INF, INF, 14 },    { 7, 0, 10, 15, INF, INF },    { 9, 10, 0, 11, INF, 2 },    { INF, 15, 11, 0, 6, INF },    { INF, INF, INF, 6, 0, 9 },    { 14, INF, 2, INF, 9, 0 }};void floyd(int src){    int i = src, j, k,weight;    // (1)确定中间点k    for (k = 0; k < NODE_COUNT; k++){        //for (i = 0; i < NODE_COUNT; i++){            // (2)更新i->j的权值            for (j = 0; j < NODE_COUNT; j++){                if (maps[i][k] != INF && maps[k][j] != INF){                    weight = maps[i][k] + maps[k][j];                    if (maps[i][j] > weight){                        maps[i][j] = weight;                    }                }               }        //}    }}void main(void){    int i = 0,j = 0;    floyd(0);    for (i = 0; i < NODE_COUNT; i++)        printf("%d:::%d\n", i, maps[0][i]);}

但是有时候我们需要知道该最短路径怎么办呢?
我们需要将第二步细化:(2)更新所有i->j的权值
这里我们加入一个记录路径的变量path;再(1)之前我们需要对path进行初始化;
调整后的算法流程为:
(1)初始化path,将INF全部设为不能走通的路径;可走通的话就讲其前驱记下;比如:

(i,j,INF)=>path[i][j]=1;(i,j,10)=>path[i][j]=i;

(2)确定一个中间点k
(3)更新所有i->j的权值,同时更新路径
maps[i][k]+maps[k][j]<maps[i][j];path[i][j]=path[k][j];maps[i][j]=maps[i][k]+maps[k][j];

更新后的算法程序为:

void floyd(int src){    int i , j, k,weight;    for (i = 0; i < NODE_COUNT; i++){        for (j = 0; j < NODE_COUNT; j++){            if (maps[i][j] == INF)                path[i][j] = -1;//表示  i -> j 不通             else                path[i][j] = i;// 表示 i -> j 前驱为 i        }    }    // 只求第src个点到各个点的最短路径    i = src;    // (1)确定中间点k    for (k = 0; k < NODE_COUNT; k++){        //for (i = 0; i < NODE_COUNT; i++){            // (2)更新i->j的权值            for (j = 0; j < NODE_COUNT; j++){                if (maps[i][k] != INF && maps[k][j] != INF){                    // 更新权值                    weight = maps[i][k] + maps[k][j];                    if (maps[i][j] > weight){                        maps[i][j] = weight;                        // 更新路径                        path[i][j] = k;                        //path[i][j] = path[k][j];                    }                }               }        //}    }}

打印路径输出结果:

    int from = 0, to = 3;    printf("%d",to);    while (path[from][to] != from) {        printf("<-%d",path[from][to]);        to = path[from][to];    }    printf("<-%d",from);    printf("\n");

输出结果为倒序输出。

0 0
原创粉丝点击