4种最短路算法的实现

首先是邻接表形式的Bellman_Ford算法,他的复杂度是O(|E||V|),他的优势在于可以计算有负边存在的情况

struct edge{int from,to,cost;};
int r,n;//r代表边的数量,n代表点的数量
edge E[maxr];
int d[maxn];
void Bellman_ford(int s){
        fill(d,d+n,INF);
        d[s]=0;
        while(true){
                bool update=false;
                for(int i=0;i<r;i++){
                        edge t=E[i];
                        if(d[t.from]!=INF && d[t.to] > d[t.from] + t.cost){
                                d[t.to]=d[t.from] + t.cost;
                                update=true;
                        }
                        //这是无向图情况下的添加的更新,如果是有向图就不需要这一步
                        if(d[t.to]!=INF && d[t.from] > d[t.to] + t.cost){
                                d[t.from]=d[t.to] + t.cost;
                                update=true;
                        }
                }
                if(!update) break;
        }
        return;
}
int main(){
        cin >> r >> n;
        for(int i=0;i<r;i++){
                int x,y,val;
                scanf("%d%d%d",&x,&y,&val);
                x--;y--;
                E[i]=(edge){x,y,val};
        }
        Bellman_ford(0);
        cout << d[n-1] << endl;
        return 0;
}

接下来是邻接矩阵形式的dijkstra算法,他的复杂度是O(|v|^2),复杂度上这个和上面的算法都差不多,但是他不能计算有负边的情况。相对于优先队列优化过的dijkstra算法他要好写很多。

int r,n;
int cost[maxn][maxn],d[maxn];
bool used[maxn];

void dijkstra(int s){
        fill(d,d+n,INF);
        fill(used,used+n,false);
        d[s]=0;
        while(true){
                int v=-1;
                for(int i=0;i<n;i++)
                //从剩下的点中寻找出最短距离的点
                        if(!used[i] && (v==-1 || d[i]<d[v])) v=i;
                if(v==-1) break;//如果所有的点都不可以选那么就退出
                used[v]=true;
                for(int i=0;i<n;i++)//更新所有点的最短距离
                        d[i]=min(d[i],d[v]+cost[v][i]);
        }
        return;
}
int main(){
        cin >> r >> n;
        //注意点之间的花费如果题中没有那么就是INF
        for(int i=0;i<maxn;i++)
                for(int j=0;j<maxn;j++)
                        cost[i][j]=INF;
        while(r--){
                int x,y,val;
                scanf("%d%d%d",&x,&y,&val);
                x--;y--;
                if(cost[x][y]>val){//有的题中需要考虑重边的情况,但是前面和后面的两种算法可以不用考虑重边的情况
                        cost[x][y]=val;
                        cost[y][x]=val;
                }
        }
        dijkstra(0);
        cout<<d[n-1]<<endl;
        return 0;
}

下面是用优先队列优化过的dijkstra算法,他的复杂度是O(|E|log|V| )

typedef pair<int,int> p;
struct edge{int to,cost;};
int n,r;
vector<edge> E[maxn];//存储与其相连的所有顶点
int d[maxn];

void dijkstra(){
        fill(d,d+n,INF);
        d[0]=0;
        priority_queue< p,vector<p>,greater<p> > que;//设置一个小值优先的优先队列
        que.push(p(0,0));
        while(!que.empty()){
                p now=que.top();que.pop();
                int dist=now.first,v=now.second;
                if(dist > d[v]) continue;//这个时候就没必要更新了
                int len=E[v].size();
                for(int i=0;i<len;i++){//列举所有顶点,自身更新后将还可以更新的点入队
                        edge t=E[v][i];
                        int newdist=t.cost + d[v];
                        if(newdist < d[t.to]){
                                d[t.to]=newdist;
                                que.push(p(d[t.to],t.to));
                        }
                }
        }
        return;
}
int main(){
        cin >> r >> n;
        while(r--){
                int x,y,val;
                scanf("%d%d%d",&x,&y,&val);
                x--;y--;
                E[x].push_back( (edge){y,val} );
                E[y].push_back( (edge){x,val} );
        }
        dijkstra();
        cout << d[n-1] << endl;
        return 0;
}

最后还有一种可以知道任意两点间的最短路的Floyd_warshall算法,他的优点在于不是像前面两种算法一样只能计算从0点到n点的最短路,而是可以计算任意两点间的最短路径,而且写起来非常的简单。当然将上面两个算法调整s值后也可以实现这样的功能,而且复杂度更低,所以这种算法很不常用。

int d[maxn][maxn];//d[u][v]代表边e =(u,v)的权值,不存在时设为INF,不过d[i][i]=0
int n;
void Floyd_warshall(){
	for(int k=0;k<n;k++)
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				d[i][j]=min(d[i][j],d[i][k] + d[k][j]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

门豪杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值