The shortest path algorithm: dij, SPFA

dijkstra complexity of O (n- 2 )

The basic idea: Shortest: dijkstra algorithm + output path
built side wording: built side - adjacency matrix, vector, star forward chain

  • Adjacency matrix and vector versions of:
    directly attached to the seniors blog: graph theory basics
  • Adjacency list (chain-Star forward):
#include <iostream>
#include <string.h>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
typedef long long LL;
using namespace std;
const int manx=1e5+10;
const int INF=0x3f3f3f3f;
int dis[300],vs[300],head[300];
int n,m,cou;
struct node
{
    int e,len,bf;//边的终点、边长、和这个点有相同起点的上一条边
} edge[manx<<2];
void add(int s,int e,int len)
{
    edge[cou]=node{e,len,head[s]};
    head[s]=cou++;
}
void dij(int s,int e)
{
    memset(dis,INF,sizeof(dis));
    memset(vs,0,sizeof(vs));
    vs[s]=1;
    dis[s]=0;
    int nx=s;
    while(!vs[e])
    {
        for(int i=head[nx]; ~i; i=edge[i].bf)
        {
            int nlen=edge[i].len;
            int ne=edge[i].e;
            if(dis[ne]>dis[nx]+nlen)
            {
                dis[ne]=dis[nx]+nlen;
            }
        }
        nx=-1;//标记距离最小的位置
        for(int j=1; j<=n; j++)
        {
            if(!vs[j])//j点没有走过
                if(nx==-1||dis[j]<dis[nx])
                    nx=j;
        }
        if(nx==-1)
            break;
        vs[nx]=1;
    }
}
int main()
{
    int sx,ex,len,s,e;
    while(scanf("%d%d",&n,&m),n||m)
    {
        cou=1;
        memset(head,-1,sizeof(head));
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&sx,&ex,&len);
            add(sx,ex,len);
            add(ex,sx,len);
        }
        //scanf("%d%d",&s,&e);
        s=1,e=n;
        dij(s,e);
        if(dis[e]==INF)
        {
            if(s==e)
                printf("0\n");
            else
                printf("-1\n");
        }
        else
            printf("%d\n",dis[e]);
    }
}

1, can think under these three kinds of writing, namely, how complete traversal of all sides have the same starting point of
2, dealt with the results of the apex of what is no path
3, why not solve the edge weight dij have a negative value

Optimization priority queue before the chain to star dij + complexity of O (mlogn)

m is the number of edges in the graph, n is the number of vertices

After optimization with priority queue, the first can be obtained directly from the next vertex team, eliminating the need to traverse the drawing each vertex find a vertex (and in this case if the head of the queue has traversed a vertex, i.e., VS [ pos] = 1, because a node may be put to many times, you can skip later)

Definition of a structure, the data structure contains two: the distance of the vertex to the vertex and the starting point and will be updated and the new vertex distance value into the queue, the priority structure is provided, so that a large distance sink to the tail

Code (not submitted, but the wording is probably like this too):

#include <iostream>
#include <string.h>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
typedef long long LL;
using namespace std;
#define chl (root<<1)
#define chr ((root<<1)|1)
#define mid ((l+r)>>1)
const int manx=1e5+10;
const int INF=0x3f3f3f3f;
int cou=0,head[1010],path[manx][2],dis[1010];
bool vs[1010];
struct node
{
    int e,len,bf;
} edge[manx];
void add(int s,int e,int len)
{
    edge[cou]=node{e,len,head[s]};
    head[s]=cou++;
}
struct poi
{
    int pos,len;
};
bool operator<(poi a,poi b)
{
    return a.len>b.len;
}
int dij(int s,int e)
{
    priority_queue<poi>qu;
    memset(dis,INF,sizeof(dis));
    memset(vs,0,sizeof(vs));
    //vs[s]=1;
    dis[s]=0;
    int nx=s;
    qu.push(poi{s,0});
    while(!qu.empty())
    {
        nx=qu.top().pos;
        qu.pop();
        //if(vs[nx])
        //    continue;
        vs[nx]=1;
        if(vs[e])
            break;
        for(int i=head[nx]; ~i; i=edge[i].bf)
        {
            int nlen=edge[i].len;
            int ne=edge[i].e;
            if(dis[ne]>dis[nx]+nlen)
            {
                dis[ne]=dis[nx]+nlen;
                qu.push(poi{ne,dis[ne]});
            }
        }
    }
    return dis[e];
}
int main()
{
    int n,m,s,e,ans,a,b,len;
    memset(head,-1,sizeof(head));
    scanf("%d%d%d%d",&n,&m,&s,&e);
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d%d",&a,&b,&len);
        path[i][0]=a;
        path[i][1]=b;
        add(a,b,len);
        add(b,a,len);
    }
    ans=dij(s,e);
    printf("%d\n",ans);
}
/*
5 5 1 5
1 2 2
2 3 2
2 4 2
3 5 100
4 5 2*/

An Example: 2872: NO GAME NO LIFE

SPFA desired complexity of O (kE)

E is the number of edges in the graph, k is a constant in many cases not more than 2 k (with reachable without the negative loop)

It can be solved right side there is a negative, and so on up the road dij can not handle.

Star forward chain version:

#include <iostream>
#include <string.h>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
typedef long long LL;
using namespace std;
const int manx=1e5+10;
const int INF=0x3f3f3f3f;
int dis[300],vs[300],head[300];
int n,m,cou;
struct node
{
    int e,len,bf;//边的终点、边长、和这个点有相同起点的上一条边
}edge[manx<<2];
void add(int s,int e,int len)
{
     edge[cou]=node{e,len,head[s]};
     head[s]=cou++;
}
vector<node>vt[300];
int spfa(int s)
{
    int c[300];
    queue<int>qu;
    memset(c,0,sizeof(c));
    memset(dis,INF,sizeof(dis));
    memset(vs,0,sizeof(vs));
    dis[s]=0;
    vs[s]=1;
    c[s]=1;
    //c数组判断是否有负环(并且有从源点到负环的路径),即c[s]是否大于n
    qu.push(s);
    int sx;
    while(!qu.empty())
    {
        sx=qu.front();//边的起点
        qu.pop();
        for(int i=head[sx];i;i=edge[i].bf)//i表示边的序号
        {
             int nx=edge[i].e;
             int nlen=edge[i].len;
             if(dis[sx]+nlen<dis[nx])
             {
                  dis[nx]=dis[sx]+nlen;
                  if(!vs[nx])
                  {
                       qu.push(nx);
                       vs[nx]=1;
                       c[nx]++;//nx被放入队列的次数
                       if(c[nx]>n)
                         return 0;
                  }
             }
        }
        vs[sx]=0;
    }
    return 1;
}
int main()
{
    int sx,ex,len,s,e;
    while(scanf("%d%d",&n,&m),n||m)
    {
        cou=1;
        memset(head,0,sizeof(head));
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&sx,&ex,&len);
            add(sx,ex,len);
            add(ex,sx,len);
        }
        //scanf("%d%d",&s,&e);
        s=1,e=n;
        int flag=spfa(s);
        if(!flag)
          continue;
        if(dis[e]==INF)
        {
            if(s==e)
                printf("0\n");
            else
                printf("-1\n");
        }
        else
            printf("%d\n",dis[e]);
    }
}
发布了52 篇原创文章 · 获赞 26 · 访问量 3174

Guess you like

Origin blog.csdn.net/qq_43803508/article/details/96425507
Recommended