zoukankan      html  css  js  c++  java
  • 【算法系列学习】SPFA邻接表最短路 [kuangbin带你飞]专题四 最短路练习 F

    https://vjudge.net/contest/66569#problem/F

    题意:判断图中是否存在负权回路

    首先,介绍图的邻接表存储方式

    数据结构:图的存储结构之邻接表

    邻接表建图,类似于头插法建单链表

    head[x]:以x为源点的第一条边,初始值为-1.

    struct edge

    {

      int to;

      int weight;

      int next;
    }e[maxn];

    to表示被指向的点;weight表示这条边的权重;next表示源点同为x的下一条边,这是遍历以x为源点的的关键

    SPFA算法中的队列与BFS不同的是,每个点都可以在重复进入队列,而且进入队列总次数大于顶点总数说明该图存在负环。这是因为每个点的估计最短路可能在出队列后被更新,这样这个点就可以再次进入队列去更新其他点。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<string>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<algorithm>
      7 #include<queue>
      8 using namespace std;
      9 const int maxn=5205;
     10 const int inf=0x3f3f3f3f;
     11 int n,m,w;
     12 struct edge
     13 {
     14     int to;
     15     int time;
     16     int next;
     17 }e[maxn];
     18 int head[505];
     19 
     20 int Spfa(int src)
     21 {
     22     //记录每个顶点到src的距离,除了src,其余点都初始化为无穷大 
     23     int dis[505];
     24     memset(dis,inf,sizeof(dis));
     25     dis[src]=0;
     26     //记录每个顶点进入队列的总次数,大于n说明有负环 
     27     int cnt[505];
     28     memset(cnt,0,sizeof(cnt));
     29     //记录是否在队列中 
     30     bool inque[505];
     31     memset(inque,0,sizeof(inque));
     32     queue<int> Q;
     33     //源点进如队列 
     34     Q.push(src);
     35     inque[src]=1;
     36     cnt[src]++;
     37     while(!Q.empty())
     38     {
     39         int q=Q.front();
     40         Q.pop();
     41         //记录已经出队列 
     42         inque[q]=0;
     43         //邻接表,i表示边 
     44         for(int i=head[q];i!=-1;i=e[i].next)
     45         {
     46             //对每个点进行松弛,逐渐逼近最小值 
     47             if(dis[q]+e[i].time<dis[e[i].to])
     48             {
     49                 dis[e[i].to]=dis[q]+e[i].time;
     50                 //如果更新成功而且当前不在队列中,进入队列且总次数加1 
     51                 if(!inque[e[i].to])
     52                 {
     53                     inque[e[i].to]=1;
     54                     cnt[e[i].to]++;
     55                     Q.push(e[i].to);
     56                     //说明存在负环 
     57                     if(cnt[e[i].to]>n)
     58                     {
     59                         return 1;
     60                     }
     61                 }
     62             }
     63         }
     64     }
     65     return 0;
     66 }
     67 int main()
     68 {
     69     int T;
     70     scanf("%d",&T);
     71     int x,y,t;
     72     while(T--)
     73     {
     74         memset(head,-1,sizeof(head));
     75         scanf("%d%d%d",&n,&m,&w);
     76         int tot=0;
     77         for(int i=1;i<=m;i++)
     78         {
     79             scanf("%d%d%d",&x,&y,&t);
     80             e[tot].to=y;
     81             e[tot].time=t;
     82             e[tot].next=head[x];
     83             head[x]=tot++;
     84             e[tot].to=x;
     85             e[tot].time=t;
     86             e[tot].next=head[y];
     87             head[y]=tot++;
     88         }
     89         for(int i=1;i<=w;i++)
     90         {
     91             scanf("%d%d%d",&x,&y,&t);
     92             e[tot].to=y;
     93             e[tot].time=-t;
     94             e[tot].next=head[x];
     95             head[x]=tot++;
     96         }
     97         int ans=Spfa(1);
     98         if(ans==1)
     99         {
    100             puts("YES");
    101         }
    102         else
    103         {
    104             puts("NO");
    105         }
    106     }
    107     return 0;
    108  } 
    邻接表+SPFA

    理论上以任意一点为源点都是可以的,顶点的数据范围是1~N,所以Spfa(1)或Spfa(n)都可以AC,其他的具体值不可以

  • 相关阅读:
    MATLAB调用VISUAL STUDIO 编写的C++函数
    卡尔曼滤波
    资料(不定时更新)
    20201207-总结
    20201126-1 每周例行报告
    20201120-1 每周例行报告
    作业要求 20201112-1 每周例行报告
    20201105-1 每周例行报告
    作业要求 20201029-1 每周例行报告
    作业要求 20201022-1 每周例行报告
  • 原文地址:https://www.cnblogs.com/itcsl/p/6680143.html
Copyright © 2011-2022 走看看