最短路_Dijkstra

暑假集训图论周,唉~被虐,不够努力。周末总结一下吧。

本博客参考网上各种资源。如有雷同,不甚荣幸。

Dijkstra:

非常经典的算法。应用贪心的思想,选择距离短的,扩充源集合。

一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。

首先有个集合S已知了其内部的最短路,现在要从图中加入一个点到集合S,使集合S里的最短路仍让正确,这时要在图中找一个里S集合

最近的点,加入集合S然后以该点为起点更新dis数组。

int a[MAXN][MAXN];
int d[MAXN];
int N;

int Dijkstra (int s,int e){
    
    int v[MAXN];   //标记已经找到的S数组。
    memser(v,0,szieof(v));
    fill(d,d+n+1,INF);
    d[s]=0;
    while (1){
        int k=-1;
        for (int i=1;i<=n;i++){    //找出其他的点到S数组最近的点
            if (v[i]==0&&(k==-1||d[i]<d[v])){
                k=1;
            }
        }
        if (k==-1){  //没找到表示最短路寻找完毕。
            break;
        }
        v[k]=1;
        for (int i=1;i<=n;i++){  //更新dis数组,
            d[i]=min(d[i],d[k]+a[k][i]);
        }
    }
    return d[t]==INF?-1:d[t];
}

当然,Dijkstra还可以用优先队列进行优化,降低时间复杂度。内容大多一样。
int m,n;
int d[MAXN];
int r[MAXN];
typedef pair<int,int >P;
 
struct Edge{       
    int v,w;
    Edge(int v, int w){
        this -> v = v;
        this -> w = w;
    }
};

vector <Edge> G[MAXN];

priority_queue<P,vector<P>,greater<P> >q; 

void dij(int s){
    while (!q.empty()) q.pop();
    for (int i=1;i<=n;i++){
        d[i]=INF;
    }
    d[s]=0;
    q.push(P(0,1));

    while (!q.empty()){

        P g=q.top();q.pop(); //优先队列,优化找最近的点的时间。
        int k=g.second;

        for (int i=0;i<G[k].size();i++){//当然邻接表也可以减少跟新次数
            Edge p=G[k][i];
            if (d[p.v]>d[k]+p.w+r[p.v]){
                d[p.v]=d[k]+p.w+r[p.v];
                q.push(P(d[p.v],p.v));
            }
        }
    }
}

poj_3628_Silver Cow Party 简单的最短路。每个农场都奶牛们要到X农场里参加聚会,N个农场间有M挑单向路,求出奶牛往返要的最大时间。

两次Dijkstra,第二次要把邻接矩阵转置,

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

#define INF 100000000
#define MAXN 1005

int n,m,x;
int a[MAXN][MAXN];
int b[MAXN][MAXN];
int d0[MAXN];
int d1[MAXN];

void dijkstra (int *d,int x,int a[][MAXN]){
    int v[MAXN];
    for (int i=0;i<MAXN;i++){
        d[i]=INF;
        v[i]=0;
    }
    d[x]=0;
    while (1){
        int k=-1;
        for (int i=1;i<=n;i++){
            if (v[i]==0&&(k==-1||d[i]<d[k]))
                k=i;
        }
        if (k==-1){
            break;
        }
        v[k]=1;
        for (int i=1;i<=n;i++){
            d[i]=min(d[i],d[k]+a[k][i]);
        }
    }
}

void transpose (int a[][MAXN],int b[][MAXN]){
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
            b[i][j]=a[j][i];
        }
    }
}

int main(){
    cin>>n>>m>>x;
    int u,v,w;
    for (int i=0;i<MAXN;i++){
        for (int j=0;j<MAXN;j++){
            a[i][j]=INF;
        }
    }
    for (int i=1;i<=m;i++){
        cin>>u>>v>>w;
        a[u][v]=min(a[u][v],w);
    }

    dijkstra(d0,x,a);

    transpose(a,b); //转置,

    dijkastra(d1,x,b);
   
    int maxnum=-1;
    for (int i=1;i<=n;i++){
        maxnum=max(maxnum,d0[i]+d1[i]);
    }
    cout<<maxnum<<endl;
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值