最短路

#include<bits/stdc++.h>
using namespace std;
#define MAX 0x3f3f3f3f
#define N 1010

int nodenum, edgenum, original; //点,边,起点

struct Edge //边
{
    int u, v;
    int cost;
};

Edge edge[N];
int dis[N], pre[N];//dis是起点到这个点的最短路,pre存路径

bool Bellman_Ford()
{
    for(int i = 1; i <= nodenum; ++i) //初始化
        dis[i] = (i == original ? 0 : MAX);

    for(int i = 1; i <= nodenum - 1; ++i)//跑这么多次
        for(int j = 1; j <= edgenum; ++j)//每次跑所有的边
            if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)
            {
                dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;
                pre[edge[j].v] = edge[j].u;
            }
    bool flag = 1; //判断是否含有负权回路
    for(int i = 1; i <= edgenum; ++i)//检验最短路中是否存在负权
        if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)
        {
            flag = 0;
            break;
        }
    return flag;
}

void print_path(int root) //打印最短路的路径(反向)
{
    while(root != pre[root]) //前驱
    {
        printf("%d-->", root);
        root = pre[root];
    }
    if(root == pre[root])
        printf("%d\n", root);
}

int main()
{
    scanf("%d%d%d", &nodenum, &edgenum, &original);//点,边,起点
    pre[original] = original;
    for(int i = 1; i <= edgenum; ++i)
    {
        scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);
    }
    if(Bellman_Ford())
        for(int i = 0; i < nodenum; ++i) //起点到每个点最短路 
        {
            printf("%d\n", dis[i]);
            printf("Path:");
            print_path(i);
        }
    else
        printf("have negative circle\n");
    return 0;
}
//Dijstra   O(n^2)  
//Dijkstra对于有负边权的最短路径不支持  
  
void Dijstra()  
{  
    int i,j;  
    for(i=0; i<n; ++i)  
    {  
        dis[i]=INF;  
        vis[i]=0;  
    }  
    dis[1]=0;  
    int v;  
    for(i=1; i<=n; ++i)  
    {  
        min=INF;  
        for(j=1; j<=n; ++j)  
        {  
            if(!vis[j]&&d[j]<min) //每次找点的过程,首先这个点没有被发现,然后找一个最小点  
            {  
                min=d[j];  
                v=j;  
            }  
        }  
        vis[v]=1;  
  
        for(j=1; j<=n; ++j) //加进最小点后,再修改从源点没有被发现的点的最短路径  
        {  
            if(!vis[j]&&dis[v]+mp[v][j]<dis[j])  
                dis[j]=dis[v]+mp[v][j];  
  
        }  
  
    }  
    int ans=-1;  
    for(i=1; i<=n; ++i)  
        if(dis[i]>ans)  
            ans=dis[i];  
  
}  
  
int main()  
{  
  
  
    for(int i=0; i<n; ++i) //初始化 类似prim  
        for(int j=0; j<n; ++j)  
        {  
            if(i!=j)  
                mp[i][j]=INF;  
            else  
                mp[i][j]=0;  
        }  
  
  
    while(m--)  
    {  
        mp[i][j]=mp[j][i]=~~;  
    }  
  
  
  
    Dijstra();  
  
  
    return 0;  
  
}  
  
  
=============================================================  
  
  
//Dijstra  优先队列+邻接表   
  
//优化后复杂度为O(mlogn)  
  
  
    struct point  
{  
    int val,id;  
    point(int id,int val):id(id),val(val) {}  
    bool operator <(const point &x)const  
    {  
        return val>x.val;  
    }  
};  
void dijkstra(int s)  
{  
    memset(vis,0,sizeof(vis));  
    for(int i=0; i<n; i++)  
        dis[i]=INF;  
  
    priority_queue<point> q;  
    q.push(point(s,0));  
    vis[s]=true;  
    dis[s]=0;  
    while(!q.empty())  
    {  
        int cur=q.top().id;  
        q.pop();  
        vis[cur]=true;  
        for(int i=head[cur]; i!=-1; i=e[i].next)  
        {  
            int id=e[i].to;  
            if(!vis[id] && dis[cur]+e[i].val < dis[id])  
            {  
                dis[id]=dis[cur]+e[i].val;  
                q.push(point(id,dis[id]));  
            }  
        }  
    }  
}  
  
  
  
  
=============================================================  
  
//Floyd    O(n^3)  
  
    void Floyd()  
{  
    for(int i=0; i<n; ++i)  
        for(int j=0; j<n; ++j)  
            mp[i][j]=mp[j][i]=~~;  
  
  
    for(int i=0; i<n; ++i)  
        for(int j=0; j<n; ++j)  
            for(int k=0; k<n; ++k)  
                if(mp[j][k]>mp[j][i]+mp[i][k])  
                    mp[j][k]=mp[j][i]+mp[i][k];  
  
  
}  
  
  
=============================================================  
  
  
//Spfa 邻接矩阵   O(kE)E为边数,k一般为2或3  
//可以计算带负环的回路  
  
  
    void Spfa()  
{  
    int i,j;  
    for(int i=0; i<n; ++i)  
    {  
        d[i]=INF;  
        vis[i]=0;  
    }  
  
    queue<int>q;  
    q.push(start);  
    d[start]=0;  
    vis[start]=1;  
    while(!q.empty())  
    {  
        int v=q.front();  
        q.pop();  
        vis[v]=0;   // 这点别忘记  
  
        for(i=0; i<n; ++i)  
        {  
            if(d[i]>d[v]+mp[v][i])  
            {  
                d[i]=d[v]+mp[v][i];  
                if(!vis[i])  
                {  
                    q.push(i);  
                    vis[i]=1;  
  
                }  
  
            }  
  
        }  
  
  
    }  
    int ans=-1;  
    for(i=1; i<=n; ++i)  
        if(d[i]>ans)  
            ans=d[i];  
  
  
}  
  
  
int main()  
{  
    for(int i=0; i<n; ++i)  
        for(int j=0; j<n; ++j)  
        {  
            if(i!=j)  
                mp[i][j]=INF;  
            else  
                mp[i][j]=0;  
        }  
  
    while(m--)  
    {  
        mp[i][j]=mp[j][i]=~~;  
    }  
  
  
    Spfa();  
  
    return 0;  
}  
  
  
=============================================================  
  
  
//Spfa 邻接表(推荐)  
  
  
    struct node  
{  
    int v;  
    int next;  
    int cost;  
} Edge,e[M];  
  
  
//Insert  
//无向图的spfa的边要存两遍  
  
void addEdge()  
{  
    mp[cnt].v=to;  
    mp[cnt].cost=cost;  
    mp[cnt].next=headlist[from];  
    headlist[from]=cnt++;  
    mp[cnt].v=to;  
    mp[cnt].cost=cost;  
    mp[cnt].next=headlist[from];  
    headlist[from]=cnt++;  
  
}  
  
//  
  
void Spfa()  
{  
    int i,j;  
  
    for(i=0; i<n; ++i)  
    {  
        d[i]=INF;  
        vis[i]=0;  
  
    }  
  
    d[start]=0;  
    vis[start]=1;  
    queue<int>q;  
    q.push(start);  
    while(!q.empty())  
    {  
        int v==q.front();  
        q.pop();  
        vis[v]=0;  
        for(i=headlist[v]; i!=-1; i=mp[i].next)  
        {  
            int b=mp[i].v;  
            if(d[b]>d[v]+mp[i].cost)  
            {  
                d[b]=d[v]+mp[i].cost;  
                if(!vis[b])  
                {  
                    vis[b]=1;  
                    q.push(b);  
  
                }  
            }  
  
        }  
  
  
  
    }  
    int ans=-1;  
    for(i=1; i<n; ++i)  
    {  
        if(d[u]>ans)  
            ans=d[i];  
  
    }  
  
  
}  
  
  
int main()  
{  
  
    //for(i=1; i<=n; i++)  
    //   headlist[i]=-1;  
    memset(head,-1,sizeof(head));  
  
    cnt=0;  
    cin>>from>>to>>cost;  
    // Insert(edge1,head1,u,v,w);  
    // Insert(edge2,head2,v,u,w);  
  
}  
  
  
  
最短路问题(short-path problem),从某点出发到达另一点所经过的路径权值相加最小的一条路径,就是最短路径。

经典的也是最容易掌握的方法Floyd,Dijkstra两种算法。

1.Floyd算法

Floyd算法可以求解的是任意两点的最短路径,功能强大,因此复杂度也很高,但是非常的好懂。

思想很简单,两点的最短路径无非就是直接从一点到另一点,要么就是中间还存在着其他的点。因此只需要暴力枚举中间点,看看存不存在中间路径长度大于直接路径的长度即可。

给出模板(附带记录路径)

[cpp] view plain copy
#include <bits/stdc++.h>  
#define inf 0x3f3f3f3f  
using namespace std;  
int G[105][105];  
int n,m;//n边m点  
int next[105][105];  
void init()  
{  
    cin>>n>>m;  
    for(int i=0; i<=n; i++)//初始化  
    {  
        for(int j=0; j<=n; j++)  
        {  
            if(i==j)  
                G[i][j]=G[j][i]=0;  
            else G[i][j]=G[j][i]=inf;  
        }  
    }  
    for(int i=0; i<m; i++)  
    {  
        int x,y,w;  
        cin>>x>>y>>w;  
        if(G[x][y]>w)//有些题目坑人给重复路径  
            G[x][y]=G[y][x]=w;  
    }  
}  
void printpath(){  
    int st=1,ed=n;  
    while(st!=ed){  
        cout<<st<<"->";  
        st=next[st][ed];  
    }  
    cout<<ed<<endl;  
}  
void Floyd()  
{  
    for(int i=1; i<=n; i++)//初始化路径  
        for(int j=1; j<=n; j++)  
            next[i][j]=j;  
  
    for(int k=1; k<=n; k++)  
        for(int i=1; i<=n; i++)  
            for(int j=1; j<=n; j++)  
                if(G[i][j]>G[i][k]+G[k][j])  
                {  
                    G[i][j]=G[i][k]+G[k][j];  
                    next[i][j]=next[i][k];  
                }  
    cout<<G[1][n]<<endl;  
    printpath();  
}  
  
int main()  
{  
    init();  
    Floyd();  
    return 0;  
}  

代码非常的简洁明了。是最容易弄懂的一个算法。但是复杂度偏高,针对有些题目没必要全部算出最短路,只需要算出单点的最短路。因此有时候复杂度会超限。


2.Dijkstra算法

说实话Dijkstra算法有点像最小生成树,也是开一个数组然后不断更新更新。

Dijkstra算法是先纳入起始点到点集合,然后dis[j]记录的是这个点集合到这个j这个点的距离。因此不断的去纳入新的点,去更新现有的距离。

给出一个带记录路径的模板

[cpp] view plain copy
#include <bits/stdc++.h>  
#define inf 0x3f3f3f3f  
using namespace std;  
int G[105][105];  
int n,m;//n边m点  
bool vis[105];  
int dis[105],pre[105];  
void init()  
{  
    cin>>n>>m;  
    for(int i=0; i<=n; i++)//初始化  
    {  
        for(int j=0; j<=n; j++)  
        {  
            if(i==j)  
                G[i][j]=G[j][i]=0;  
            else G[i][j]=G[j][i]=inf;  
        }  
    }  
    for(int i=0; i<m; i++)  
    {  
        int x,y,w;  
        cin>>x>>y>>w;  
        if(G[x][y]>w)//有些题目坑人给重复路径  
            G[x][y]=G[y][x]=w;  
    }  
}  
  
void printpath(int v){  
    int p=n,cnt=0;  
    int ans[105];  
    while(p!=v){  
        ans[cnt++]=p;  
        p=pre[p];  
    }  
    cout<<v;  
    for(int i=cnt-1;i>=0;i--)  
        cout<<"->"<<ans[i];  
    cout<<endl;  
}  
  
void Dijkstra(int v)  
{  
    int minnum,next;  
    for(int i=0; i<=n; i++)  
    {  
        dis[i]=G[v][i];  
        vis[i]=0;  
        if(i!=v&&G[v][i]!=inf)  
            pre[i]=v;  
        else pre[i]=-1;  
    }  
    vis[v]=1;  
    dis[v]=0;  
    for(int i=1; i<n; i++) //每次纳入一个点,需要操作n-1次  
    {  
        minnum=inf;  
        for(int j=1; j<=n; j++)//找出距离最小的点当做下一个操作点  
        {  
            if(!vis[j]&&minnum>dis[j])  
            {  
                minnum=dis[j];  
                next=j;  
            }  
        }  
        if(minnum==inf)  
            break;  
        vis[next]=1;  
        for(int j=1; j<=n; j++) //更新这个操作点到其他点的距离  
        {  
            if(!vis[j] && G[next][j]!=inf && dis[next]+G[next][j]<dis[j])  
            {  
                dis[j]=G[next][j]+dis[next];  
                pre[j]=next;  
            }  
        }  
    }  
    cout<<dis[n]<<endl;  
    printpath(v);  
}  
  
int main()  
{  
    init();  
    Dijkstra(1);//起始点到最后个点的距离  
    return 0;  
}  

3.Bellman-Ford算法

从百度上弄来的代码,很直观很好理解,对每条边,跑n-1次,每次松弛(妈的,什么叫松弛!?其实就是判断纳入这条边之后对最短路有没有影响,在具体点就是这行代码

[cpp] view plain copy
dis[edge[j].v] > dis[edge[j].u] + edge[j].cost  
)我是不太喜欢那些被装饰的语句的,能简单就简单,能用代码讲清楚的就别搞七搞八。
另spfa是该算法的队列优化

[cpp] view plain copy
#include<bits/stdc++.h>  
using namespace std;  
#define MAX 0x3f3f3f3f  
#define N 1010  
  
int nodenum, edgenum, original; //点,边,起点  
  
struct Edge //边  
{  
    int u, v;  
    int cost;  
};  
  
Edge edge[N];  
int dis[N], pre[N];//dis是起点到这个点的最短路,pre存路径  
  
bool Bellman_Ford()  
{  
    for(int i = 1; i <= nodenum; ++i) //初始化  
        dis[i] = (i == original ? 0 : MAX);  
  
    for(int i = 1; i <= nodenum - 1; ++i)//跑这么多次  
        for(int j = 1; j <= edgenum; ++j)//每次跑所有的边  
            if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序一定不能反~)  
            {  
                dis[edge[j].v] = dis[edge[j].u] + edge[j].cost;  
                pre[edge[j].v] = edge[j].u;  
            }  
    bool flag = 1; //判断是否含有负权回路  
    for(int i = 1; i <= edgenum; ++i)//检验最短路中是否存在负权  
        if(dis[edge[i].v] > dis[edge[i].u] + edge[i].cost)  
        {  
            flag = 0;  
            break;  
        }  
    return flag;  
}  
  
void print_path(int root) //打印最短路的路径(反向)  
{  
    while(root != pre[root]) //前驱  
    {  
        printf("%d-->", root);  
        root = pre[root];  
    }  
    if(root == pre[root])  
        printf("%d\n", root);  
}  
  
int main()  
{  
    scanf("%d%d%d", &nodenum, &edgenum, &original);//点,边,起点  
    pre[original] = original;  
    for(int i = 1; i <= edgenum; ++i)  
    {  
        scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);  
    }  
    if(Bellman_Ford())  
        for(int i = 1; i <= nodenum; ++i) //起点到每个点最短路  
        {  
            printf("%d\n", dis[i]);  
            printf("Path:");  
            print_path(i);  
        }  
    else  
        printf("have negative circle\n");  
    return 0;  
}  


根据pat考试中L2-001题目整理的完美模板,包含一切

[cpp] view plain copy
#include<bits/stdc++.h>  
using namespace std;  
#define inf 0x3f3f3f3f  
int n,m,st,ed;  
int num[505],vis[505],dis[505],pre[505],sum[505],cnt[505];  
//每个节点的人数。是否走过。最短距离。前驱。最大救援人数数量.方案数  
int G[505][505];//图  
void path(int i){  
    if(pre[i]!=-1){  
        path(pre[i]);  
        cout<<pre[i]<<" ";  
    }  
}  
int main()  
{  
    cin>>n>>m>>st>>ed;  
    for(int i=0;i<n;i++){  
        for(int j=0;j<n;j++){  
            if(i==j)  
                G[i][j]=0;  
            else G[i][j]=inf;  
        }  
    }  
    for(int i=0;i<n;i++)  
        cin>>num[i];  
    for(int i=0;i<m;i++){  
        int x,y,w;  
        cin>>x>>y>>w;  
        G[x][y]=G[y][x]=w;  
    }  
    memset(dis,inf,sizeof(dis));  
    memset(vis,0,sizeof(vis));  
    memset(cnt,0,sizeof(cnt));  
    memset(sum,0,sizeof(sum));  
    memset(pre,-1,sizeof(pre));  
  
    dis[st]=0;  
    vis[st]=1;  
    cnt[st]=1;  
    sum[st]=num[st];  
  
    for(int i=0;i<n;i++){  
        int minnum=inf,next=st;  
        for(int j=0;j<n;j++){  
            if(vis[j]==0&&minnum>dis[j]){  
                minnum=dis[j];  
                next=j;  
            }  
        }  
        vis[next]=1;  
        for(int j=0;j<n;j++){  
            if(vis[j]==0){  
                if(dis[j]>dis[next]+G[next][j]){  
                    dis[j]=dis[next]+G[next][j];  
                    sum[j]=num[j]+sum[next];  
                    cnt[j]=cnt[next];  
                    pre[j]=next;  
                }  
                else if(dis[j]==dis[next]+G[next][j]){  
                    cnt[j]=cnt[next]+cnt[j];  
                    if(sum[j]<sum[next]+num[j]){  
                        sum[j]=sum[next]+num[j];  
                        pre[j]=next;  
                    }  
                }  
            }  
        }  
    }  
    cout<<cnt[ed]<<" "<<sum[ed]<<endl;  
    path(ed);  
    cout<<ed<<endl;  
    return 0;  
}  


DIJK
C++代码  收藏代码
#define inf 0x3fffffff  
#define M 105  
  
int dist[M], map[M][M], n;  
bool mark[M];  
  
void init ()  
{  
    int i, j;  
    for (i = 1; i <= n; i++)    //i==j的时候也可以初始化为0,只是有时候不合适  
        for (j = 1; j <= n; j++)  
            map[i][j] = inf;  
}  
  
void dijk (int u)  
{  
    int i, j, mins, v;  
    for (i = 1; i <= n; i++)  
    {  
        dist[i] = map[u][i];  
        mark[i] = false;  
    }  
    mark[u] = true;  
    dist[u] = 0;    //既然上面的map当i==j时不是0,就要这句  
    while (1)  
    {  
        mins = inf;  
        for (j = 1; j <= n; j++)  
            if (!mark[j] && dist[j] < mins)  
                mins = dist[j], v = j;  
        if (mins == inf)  
            break;  
        mark[v] = true;  
        for (j = 1; j <= n; j++)  
            if (!mark[j] && dist[v] + map[v][j] < dist[j])  
                dist[j] = dist[v] + map[v][j];  
    }  
}  

②Floyd 
C++代码  收藏代码
#define inf 0x3fffffff  //注意,太大会溢出  
#define M               //最大点数  
int n, dist[M][M];           //n:实际点数  
  
void init ()            //有时候需要初始化  
{  
    int i, j;  
    for (i = 1; i <= n; i++)  
        for (j = i + 1; j <= n; j++)  
            dist[i][j] = dist[j][i] = inf;  
}  
  
void floyd ()  
{  
    int i, j, k;  
    for (k = 1; k <= n; k++)  
        for (i = 1; i <= n; i++)  
            for (j = 1; j <= n; j++)    //有的题目会溢出就要自己变通了  
                if (dist[i][k] + dist[k][j] < dist[i][j])  
                        dist[i][j] = dist[i][k] + dist[k][j];  
}  

③vector后插的SPFA 
C++代码  收藏代码
#define inf 0x3fffffff  
#define M 105    //最大点数  
struct son{  
    int v, w;  
};  
vector<son> g[M];  
bool inq[M];       //入队列标记  
int dist[M], n;    //n:实际点数  
  
void init ()  
{  
    for (int i = 1; i <= n; i++)  
        g[i].clear();  
}  
  
void spfa (int u)  
{  
    int i, v, w;  
    for (i = 1; i <= n; i++)  
    {  
        dist[i] = inf;  
        inq[i] = false;  
    }  
    queue<int> q;  
    q.push (u);  
    inq[u] = true;  
    dist[u] = 0;  
    while (!q.empty())  
    {  
        u = q.front();  
        q.pop();  
        inq[u] = false;  
        for (i = 0; i < g[u].size(); i++)  
        {  
            v = g[u][i].v;  
            w = g[u][i].w;  
            if (dist[u] + w < dist[v])  
            {  
                dist[v] = dist[u] + w;  
                if (!inq[v])  
                {  
                    q.push (v);  
                    inq[v] = true;  
                }  
            }  
        }  
    }  
}  

④模拟前插的SPFA(多数情况下比③快,数据较为复杂就会看出来) 
C++代码  收藏代码
#define inf 0x3fffffff  
#define M 1005  //最大点数  
  
struct edge{  
    int v, w, next;  
}e[10005];      //估计好有多少条边  
  
int pre[M], cnt, dist[M], n;  
bool inq[M];  
//注意初始化  
void init ()  
{  
    cnt = 0;  
    memset (pre, -1, sizeof(pre));  
}  
//注意双向加边   
void addedge (int u, int v, int w)    //加边函数,慢慢模拟就会明白的  
{  
    e[cnt].v = v;  
    e[cnt].w = w;  
    e[cnt].next = pre[u];       //接替已有边  
    pre[u] = cnt++;             //自己前插成为u派生的第一条边  
}  
  
void spfa (int u)  
{  
    int v, w, i;  
    for (i = 1; i <= n; i++) //对于从1到n的编号  
        dist[i] = inf, inq[i] = false;  
    dist[u] = 0;  
    queue<int> q;  
    q.push (u);  
    inq[u] = true;  
    while (!q.empty())  
    {  
        u = q.front();  
        q.pop();  
        inq[u] = false;  
        for (i = pre[u]; i != -1; i = e[i].next)  
        {  
            w = e[i].w;  
            v = e[i].v;  
            if (dist[u] + w < dist[v])  
            {  
                dist[v] = dist[u] + w;  
                if (!inq[v])  
                {  
                    q.push (v);  
                    inq[v] = true;  
                }  
            }  
        }  
    }  
}  
#include <bits/stdc++.h>
using namespace std;
const int maxn = 99999;
const int INF = 0x7fffffff;
typedef pair<int, int> P;
struct edge
{
    int to, cost;
};

int V;
vector<edge> G[maxn];
int d[maxn];
//
//bool operator <(const P a, const P b) {
//    return a.first > b.first;
//}
void dijkstra(int s)
{
    priority_queue<P, vector<P>, greater<P> > que;
    fill(d, d + V + 2, INF);
    d[s] = 0;
    que.push(P(0, s));
    while (!que.empty()) {
        P p = que.top();
        que.pop();
        int v = p.second;
        if (d[v] < p.first) continue;//到v点的距离如果已经被更新 这无须执行以下操作
        for (int i = 0; i < G[v].size(); ++i) {
            edge e= G[v][i];
            if (d[e.to] > d[v] +e.cost) {
                d[e.to] = d[v] + e.cost;
                que.push(P(d[e.to], e.to));
            }
        }
    }
}
int main()
{
    int m;
    cin >> V >> m;
    for (int i = 0; i < m; ++i) {
        int from, to, cost;
        cin >> from >> to >> cost;
        edge var;
        var.to = to;
        var.cost = cost;
        G[from].push_back(var);
        var.to = from;
        G[to].push_back(var);
    }
    for (int i = 1; i <= V; ++i) {
        cout << i << ":";
        for(int j = 0; j < G[i].size(); ++j)
            cout << G[i][j].to << " ";
        cout << endl;
        }
    dijkstra(1);
    for (int i = 1; i <= V; ++i)
        cout << d[i] << endl;
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x7fffffff;
#define MEM(arr) memset(arr, 0, sizeof(arr))
const int maxn = 5000;
typedef struct node
{
    int to, cost;
}edge;
vector<edge> v[maxn];
int in_sum[maxn];
int in_que[maxn];
int n, m, d[maxn];

bool SPFA(int source)
{
    deque<int> q;
    for (int i = 1; i <= n; ++i) {
        d[i] = i == source ? 0 : INF;
    }

    q.push_back(source);
    in_sum[source]++;
    in_que[source] = 1;
    while (!q.empty()) {
        int curr = q.front();
        q.pop_front();
        in_que[curr] = 0;
        for (int i = 0; i < v[curr].size(); ++i) {
            int to = v[curr][i].to;
            if (d[curr] < INF && d[to] > d[curr] + v[curr][i].cost) {
                d[to] = d[curr] + v[curr][i].cost;
                if (in_que[to] == 0) {
                    in_que[to] = 1;
                    if(++in_sum[to] == n)
                        return false;
                    }
                     if(!q.empty())
                    {
                        if(d[to] > d[q.front()]) q.push_back(to);
                        else q.push_front(to);
                    }else q.push_back(to);
            }

        }
    }
    return true;
}

int main()
{
    while (cin >> n >> m) {
        MEM(in_sum);
        MEM(in_que);
        MEM(d);
        for (int i = 0; i <= n; ++i) {
            v[i].clear();
        }
        for (int i = 1; i <= m; ++i) {
            int vfrom, vto, vcost;
            cin >> vfrom >> vto >> vcost;
            edge var;
            var.to = vto;
            var.cost = vcost;
            v[vfrom].push_back(var);
        }
//        for (int i = 1; i <= n; ++i) {
//                cout << i << ":";
//            for(int j = 0; j < v[i].size(); ++j)
//            cout << v[i][j].to << " ";
//        cout << endl;
//        }
        if(SPFA(1))
        {
            for (int i = 1; i <=n; ++i) {
                cout << i << ":" << d[i] << endl;
            }
        }
        else cout << "-1" << endl;

    }
    return 0;
}

/*
Dijkstra的算法思想:
在所有没有访问过的结点中选出dis(s,x)值最小的x
对从x出发的所有边(x,y),更新
dis(s,y)=min(dis(s,y),dis(s,x)+dis(x,y))
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int Ni = 10000;
const int INF = 0x3f3f3f3f;

struct node{
    int x,d;
    node(){}
    node(int a,int b){x=a;d=b;}
    bool operator < (const node & a) const
    {
        if(d==a.d) return x<a.x;
        else return d > a.d;
    }
};

vector<node> eg[Ni];
int dis[Ni],n;

void Dijkstra(int s)
{
    int i;
    memset(dis,INF,sizeof(dis));
    dis[s]=0;
    //用优先队列优化
    priority_queue<node> q;
    q.push(node(s,dis[s]));
    while(!q.empty())
    {
        node x=q.top();
        q.pop();
        for(i=0;i<eg[x.x].size();i++)
        {
            node y=eg[x.x][i];
            if(dis[y.x]>x.d+y.d)
            {
                dis[y.x]=x.d+y.d;
                q.push(node(y.x,dis[y.x]));
            }
        }
    }
}

int main()
{
    int a,b,d,m;
    while(scanf("%d%d",&n,&m),n+m)
    {
        for(int i=0;i<=n;i++)
            eg[i].clear();
        while(m--)
        {
            scanf("%d%d%d",&a,&b,&d);
            eg[a].push_back(node(b,d));
            eg[b].push_back(node(a,d));
        }
        Dijkstra(1);
        printf("%d\n",dis[n]);
    }
    return 0;
}
/*
6
2 2
2 4
4 5
5 2
6 3
6 3
*/



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值