单源最短路——Dijkstra算法

单源最短路径:一个点(源点)到其余各个顶点的最短路劲

#include
#include
#define inf 99999999
int a[1002][1002];
int main()
{
    memset(a,inf,sizeof(a));///若题目有重边,则需要先将邻接矩阵初始化为inf,在后面读入边的时候再加if判断
    int dis[1002]={},book[1002]={};//book数组初始化
    int N,M,x,y,z,t,sum=0;
    scanf("%d%d",&N,&M);//读入N和M,N表示顶点个数,M表示边的条数
    //初始化邻接矩阵
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            if(i==j) a[i][j]=0;
            else a[i][j]=inf;
        }
    }
    //读入边
    for(int k=0;k<M;k++){
        scanf("%d%d%d",&x,&y,&z);
        if(z<a[x][y])//若题目有重边,则需要加这条if语句判断
        	a[x][y]=z;
    }
    //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
    for(int q=1;q<=N;q++){
        dis[q]=a[1][q];
    }
    book[1]=1;//标记源点
    //Dijkstras算法核心语句
    for(int i=1;i<=N-1;i++){
    	//找到离1号顶点最近的点
        int min=inf;
        for(int j=1;j<=N;j++){
            if(book[j]==0&&dis[j]<min){
                min=dis[j];
                t=j;
            }
        }
        book[t]=1;
        for(int o=1;o<=N;o++){
            if(a[t][o]<inf){
                if(dis[o]>dis[t]+a[t][o])
                    dis[o]=dis[t]+a[t][o];
            }
        }
    }
    //输出最终结果
    for(int k=1;k<=N;k++){
        printf("%d ",dis[k]);
        //sum+=dis[k];
    }
    //printf("%d\n",sum);
    return 0;
}
// Dijkstra算法
#include 
#include 

#define INF 20000000000000

int n;
int visit[1001];
long long state[1001];
int G1[1001][1001];

int Min()
{
    int place=0,i;
    long long min=INF;
    for(i=1;i<=n;i++)
         if(!visit[i]&&min>state[i])
         {
              min=state[i];
              place=i;
         }
    return place;
}

long long Dijkstra(int G[][1001])
{
    int u,i;
    long long sum;

    memset(visit,0,sizeof(visit));

    state[1]=0;
    for(i=2;i<=n;i++)
         state[i]=INF;

    while(1)
    {
         u=Min();
         if(u==0)break;
         visit[u]=1;
         for(i=1;i<=n;i++)
         {
              if(i==u)continue;
              if(!visit[i]&&G[u][i]&&state[i]>state[u]+G[u][i])state[i]=state[u]+G[u][i];
         }
    }
    for(i=1,sum=0;i<=n;i++)
         sum+=state[i];
    return sum;
}

int main()
{
    int s,d,w,dage,i;
    scanf("%d%d",&n,&dage);

    memset(G1,0,sizeof(G1));

    for(i=1;i<=dage;i++)
    {
         scanf("%d%d%d",&s,&d,&w);
         if(G1[s][d]==0||G1[s][d]>w)  G1[s][d]=w;
    }
    printf("%lld\n",Dijkstra(G1));

    return 0;
}
// SPFA算法
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int MAX=1005;
const int inf=0x3f3f3f3f;

struct NODE
{
     int to,len;
     NODE *next;
};

NODE *p[MAX],node[MAX*MAX];
int cou;

void add(int from,int to,int len)
{
     node[cou].next=p[from];
     node[cou].to=to;
     node[cou].len=len;
     p[from]=&node[cou++];
}

int SPFA_List(int from,int to,int n)
{
     queue<int> q;
     int dis[MAX],cnt[MAX],neg=0;
     bool inq[MAX];
     int i;
     for(i=1;i<=n;++i)
          dis[i]=inf;
     memset(cnt,0,sizeof(cnt));
     memset(inq,false,sizeof(inq));
     dis[from]=0;
     q.push(from);
     inq[from]=cnt[from]=1;
     while(!q.empty())
     {
          int now=q.front();
          q.pop();
          inq[now]=false;
          NODE *head=p[now];
          while(head!=NULL)
          {
               int v=head->to;
               int len=head->len;
               if(dis[v]>dis[now]+len)
               {
                    dis[v]=dis[now]+len;
                    if(!inq[v])
                    {
                         inq[v]=true;
                         q.push(v);
                         cnt[v]++;
                         if(cnt[v]>n)
                         {
                              neg=1;
                              break;
                         }
                    }
               }
               head=head->next;
          }
          if(neg) break;
     }
     if(neg)
     {
          cout<<"spfa_list say: exist negative circle!!!!"<<endl;
          return -1;
     }
     int ans=0;
     for(i=2;i<=n;++i)
          ans+=dis[i];
     return ans;
}

int main()
{
     int n,m,i,j,u,v,w;
     scanf("%d%d",&n,&m);

     cou=0;
     for(i=1;i<=n;++i)
          p[i]=NULL;
     //for(i=1;i<=n;++i)
     //      for(j=1;j<=n;++j)
     //           map[i][j]=inf;
     for(i=0;i<m;++i)
     {
          scanf("%d%d%d",&u,&v,&w);
          add(u,v,w);
          //if(w
     }
     printf("%d\n",SPFA_List(1,n,n));

     return 0;
}

单源最短路径算法小结
待搜索的图都指有向图(无向图类似)。储存方式均为邻接表
一、广度优先搜索(BFS)
时间复杂度:O(V+E),效率很高
适用范围:(很窄)仅适于无权边的图。即每条边长度都为1的情况
代码复杂程度:一般,需队列
二、Bellman-Ford
时间复杂度:O(VE),效率一般
适用范围:(很广)允许存在负权边,能够判断图中是否存在从源点可到达的负权环路
代码复杂程度:较易
三、有向无环图算法
时间复杂度:O(V+E),效率很高
适用范围:(很窄)仅适于有向无环图
代码复杂程度:一般,需拓扑排序
四、Dijkstra
适用范围:(一般)不允许存在负权边
这个算法复杂度取决于"取最小"(Extract-min)操作使用的算法
Extract-min操作 时间复杂度 代码复杂程度
顺序检测所有点决定最小值 O(V^2) 一般
使用Binary-Heap(优先队列) O((V+E)lgV) 较复杂
使用Fibonacci-Heap O(VlgV+E) 较复杂
五、SPFA (Shortest Path Faster Algorithm)
时间复杂度:O(kE),k为一较小常量。效率很高
适用范围:(较广),允许存在负权边,但不允许负权环路
代码复杂程度:较易,需队列
这个算法可算是 Bellman-Ford 的优化版本,去除冗余的Relax操作,效率有很大提升

你可能感兴趣的:(图论)