最短路径

 Dijkstra单源节点到其他所有节点的最短路径

#include<iostream>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

const int INFINIT=32767;
struct tableItem{
    int prevIndex;
    int dist;
    bool found;
    tableItem(int p=-1,int d=INFINIT,bool f=false):
        prevIndex(p),dist(d),found(f){}
};

int main(){
    int graph[7][7]={{0,2,INFINIT,1,INFINIT,INFINIT,INFINIT},
            {INFINIT,0,INFINIT,3,10,INFINIT,INFINIT},
            {4,INFINIT,0,INFINIT,INFINIT,5,INFINIT},
            {INFINIT,INFINIT,2,0,2,8,4},
            {INFINIT,INFINIT,INFINIT,INFINIT,0,INFINIT,6},
            {INFINIT,INFINIT,INFINIT,INFINIT,INFINIT,0,INFINIT},
            {INFINIT,INFINIT,INFINIT,INFINIT,INFINIT,1,0}};

    vector<tableItem> table(7);
    table[0].prevIndex=0;
    table[0].dist=0;
    while(1){
        int node=-1;
        int minDist=INFINIT;
        int i;
        for(i=0;i<7;i++){
            if(table[i].found==false && table[i].dist<minDist){
                minDist=table[i].dist;
                node=i;
            }
        }
        if(node==-1)
            break;
        
        table[node].found=true;
    
        for(i=0;i<7;i++){
            if(graph[node][i]<INFINIT && graph[node][i]>0){
                if(table[node].dist+graph[node][i]<table[i].dist){
                    if(table[i].found==true){
                        cerr<<"the graph include circulate route!"<<endl;
                        throw;
                    }
                    table[i].prevIndex=node;
                    table[i].dist=table[node].dist+graph[node][i];
                }
            }
        }
    }

    int end=1;
    for(;end<7;end++){
        int curr=end;
        stack<int> s;
        int prev;
        do{
            prev=table[curr].prevIndex;
            s.push(prev);
            curr=prev;
        }while(prev!=0);
        while(!s.empty()){
            cout<<s.top()<<"-->";
            s.pop();
        }
        cout<<end<<endl;
    }
    return 0;
}

分析这个算法复杂度。图中节点数是V,边数为E。最外层的while循环要循环V次,每次把一个节点的found设为true,当所有节点的found为true时循环退出。每次循环内部都要从found为false的节点中找dist最小者。因此这个过程复杂度为。更新节点的dist时,每条边最多被更新一次,总计为。所以总的复杂度为

如果是稠密图,,则上述算法复杂度为,上述算法基本上是最优的,其运行时间与边数成线性关系。

如果是稀疏图,上述算法就太慢了,我们把降下来。最外层的while循环要循环V次这是不可改变的,所以我们要缩短寻找最小dist的时间,可以使用优先队列或者配对堆

寻找所有点对的最短路径

对于稀疏图而言,更快的算法是运行V趟使用优先队列的Dijkstra算法找到所有点对的最短路径,此时的复杂度为

这里给出另一种动态规划的解法,其运算时间复杂度也为,它不是对Dijkstra算法的改进,但对于非常稠密的图可能更快,原因是它的循环更紧凑。如果存在一此负的边值但没有负的回路,那么这个算法也能正确运行,而Dijkstra算法此时是无效的。

用二维数组graph来存储图,顶点之间的最短路径用二维数组dist来存储。 初始把graph赋给dist。顶点到顶点的最短路径是:

程序是这样运行的:遍历,对于每一个k,更新所有的

#include<iostream>
#include<iomanip>
using namespace std;

const int INFINIT=32767;

int main(){
    int graph[7][7]={{0,2,INFINIT,1,INFINIT,INFINIT,INFINIT},
            {INFINIT,0,INFINIT,3,10,INFINIT,INFINIT},
            {4,INFINIT,0,INFINIT,INFINIT,5,INFINIT},
            {INFINIT,INFINIT,2,0,2,8,4},
            {INFINIT,INFINIT,INFINIT,INFINIT,0,INFINIT,6},
            {INFINIT,INFINIT,INFINIT,INFINIT,INFINIT,0,INFINIT},
            {INFINIT,INFINIT,INFINIT,INFINIT,INFINIT,1,0}};
     int path[7][7]={-1};           
    int **dist=new int *[7];
    for(int i=0;i<7;i++){
        dist[i]=new int[7];
        for(int j=0;j<7;j++)
            dist[i][j]=graph[i][j];
    }

    for(int k=0;k<7;k++){
        for(int i=0;i<7;i++){
            for(int j=0;j<7;j++){
                if(dist[i][k]+dist[k][j]<dist[i][j]){
                    dist[i][j]=dist[i][k]+dist[k][j];
                    path[i][j]=k;
                }
            }
        }
    }

    cout<<right;
    for(int i=0;i<7;i++){
        for(int j=0;j<7;j++){
            cout<<setw(8)<<dist[i][j];
        }
        cout<<endl;
    }

    for(int i=0;i<7;i++)
        delete []dist[i];
    delete []dist;

    return 0;
}

指定两点间的最短路径

使用Dijkstra算法找顶点到顶点的最短路径,当的found为true时,算法就可以终止了。

最短路径的应用

字梯游戏:一个单词通过变换一个字母可以变为另外一个单词。例如我们可以通过一系列的单词变换将zero变为five:zero-->hero-->here-->hire-->fire-->five。

这是一个无权最短路径问题,每个词是一个顶点。如果两个顶点可以通过一个字母替换相互转换的话,它们之间就有一条(无向)边。

posted @ 2010-11-03 22:04  张朝阳  阅读(520)  评论(0编辑  收藏  举报