zoukankan      html  css  js  c++  java
  • Spfa求最短路径+判负环

    spfa求最短路径,其思想就是遍历每一个点,将没有入队的点入队,从这个点开始不断修改能够修改的最小路径,直到队空。不过这里一个点可以重复入队。

    这个需要有存图的基础--------->前向星存图

    举个栗子

      

    这里有一张图,边旁边的数字为这条边的权值。旁边的图为边的编号

    用dis[i]来记录起点到i的最小路径长度(一开始都是inf)

    求最小路径,首先从起点开始,遍历起点的每一条出边,并将要修改dis[i]的出边终点(没有入队的点)入队,再不断出队,对每个队中的点进行相同的操作。

    模拟一下。

    首先将①入队。dis[1]=0。①的第一条出边的终点是②,将②入队,同时修改dis[2]=3.

    下一条出边是第四条边,终点为③,将③入队,修改dis[3]=4.

    将④入队,dis[4]=6。

    进行完这一步,①出队,同时将①标记为未入队,对②进行操作。

    ②的第一条出边的终点为①,不修改,不入队。

    next:终点为③,9+3>4,不修改 ,不入队。

    next:将⑥入队,dis[6]=10+3=13

    如此不断更新~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    来我们看一下代码

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #define spfa zhx_akioi
    using namespace std;
    long long n,m,s,head[10001],num;
    long long dis[50008],vis[50008];
    queue <long long> q;
    const int inf=2147483647;
    struct  Edge{
        int next,to,dis;
    }edge[500008];
    void add(int f,int t,int d)
    {   num++;
        edge[num].next=head[f];
        edge[num].to=t;
        edge[num].dis=d;
        head[f]=num;
    }
    void spfa()
    {      for(int i=1;i<=n;i++)
         dis[i]=inf;//最开始先把每个点到起点的距离设为无限大
        dis[s]=0;//起点到起点的距离是0
        vis[s]=1;//将起点入队,用vis标记是否在队里
        q.push(s);
        while(!q.empty())
        {int u=q.front();
          q.pop();
          vis[u]=0;
          for(int i=head[u];i;i=edge[i].next)//从出队的点开始,遍历这个点的每条出边
          { int v=edge[i].to;
              if(dis[v]>dis[u]+edge[i].dis)//如果这个点当前到起点的距离大于出队的点到起点的距离加上当前边的距离,即可以更新,就更新,并将更新的点入队
              { dis[v]=dis[u]+edge[i].dis;
                if(vis[v]==0)
              {q.push(v);
                vis[v]=1;//标记
              }
            }
          }
        }
    }
    int main()
    {
        scanf("%lld%lld%lld",&n,&m,&s);
        for(int i=1;i<=m;i++)
        {int f,t,d;
         scanf("%lld%lld%lld",&f,&t,&d);
         add(f,t,d);//存图
        }
        spfa();
        for(long long i=1;i<=n;i++)
         printf("%lld ",dis[i]);
    }

     判负环

    如果图里面没有负环,那么一个点最多入队n次。如果有点入队次数大于n次就说明有负环。

    当然还可以把spfa改成dfs版,即一直沿着某条路进行更新,如果再一次松弛到了该路径上松弛过的点,就证明有负环(可能会TLE)

    bfs版:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #define pa pair<int,int>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int inf=2147483647;
    inline ll read()
    {
        char ch=getchar();
        ll x=0; 
        bool f=0;
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') f=1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=(x<<3)+(x<<1)+(ch^48);
            ch=getchar();
        }
        return f?-x:x;
    }
    int t,n,m,head[20009],cnt,dis[20009],vis[20009],in[20009];
    struct E{
        int to,nxt,dis;
    }ed[60009];
    void init()
    {
        cnt=0;
        memset(head,0,sizeof(head));
        memset(in,0,sizeof(in));
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
    }
    void add(int fr,int to,int dis)
    {
        ed[++cnt].to=to;
        ed[cnt].dis=dis;
        ed[cnt].nxt=head[fr];
        head[fr]=cnt;
    }
    bool spfa()
    {
       queue <int> q;
        dis[1]=0;
        vis[1]=0;
        in[1]++;//in统计入队次数
        q.push(1);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int e=head[u];e;e=ed[e].nxt)
            {
                int v=ed[e].to;
                if(dis[v]>dis[u]+ed[e].dis)
                {
                    dis[v]=dis[u]+ed[e].dis;
                    if(!vis[v])
                    {
                        vis[v]=1;
                        in[v]++;
                        if(in[v]>n) return 1;
                        q.push(v);
                    }
                }
            }
        }
        return 0;
    }
    int main()
    {
        t=read();
        while(t--)
        {
            init();
            n=read();m=read();
            for(int i=1;i<=m;i++)
            {
                int fr=read(),to=read(),dis=read();
                add(fr,to,dis);
                if(dis>=0)
                  add(to,fr,dis);
            }
            if(spfa()) printf("YE5
    ");//模板题让你输出的奇奇怪怪的东西
            else printf("N0
    ");
        }
    }

    dfs版:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #define pa pair<int,int>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int inf=2147483647;
    inline ll read()
    {
        char ch=getchar();
        ll x=0; 
        bool f=0;
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') f=1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=(x<<3)+(x<<1)+(ch^48);
            ch=getchar();
        }
        return f?-x:x;
    }
    int t,n,m,head[2009],cnt,dis[2009],vis[2009],in[2009];
    int sta[2009],top;
    bool fh;
    struct E{
        int to,nxt,dis;
    }ed[6009];
    void init()
    {
        cnt=0;top=0;fh=0;
        memset(head,0,sizeof(head));
        memset(in,0,sizeof(in));
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
    }
    void add(int fr,int to,int dis)
    {
        ed[++cnt].to=to;
        ed[cnt].dis=dis;
        ed[cnt].nxt=head[fr];
        head[fr]=cnt;
    }
    void spfa(int u)
    {
        if(fh) return ;
        vis[u]=1;
        for(int e=head[u];e;e=ed[e].nxt)
        {
            if(fh) return ;
            int v=ed[e].to;
            if(dis[v]>dis[u]+ed[e].dis)
            {
                dis[v]=dis[u]+ed[e].dis;
                if(vis[v])
                {
                    fh=1;
                    return;
                }
                spfa(v);
            }
        }
        vis[u]=0;
    }
    int main()
    {
        t=read();
        while(t--)
        {
            init();
            n=read();m=read();
            for(int i=1;i<=m;i++)
            {
                int fr=read(),to=read(),dis=read();
                add(fr,to,dis);
                if(dis>=0)
                  add(to,fr,dis);
            }
            dis[1]=0;
            spfa(1);
            if(fh) printf("YE5
    ");
            else printf("N0
    ");
        }
    }
  • 相关阅读:
    未来的计划和考虑
    jquery 常用的方法
    对于页面动态加载的元素事件无效的解决方案
    Myeclipse8.5中svn插件安装方法总结
    JS读RSS
    JAVA的RSS处理
    环境:win7+ie8 IE8的F12不起作用,原因如下:
    关闭和释放JDBC
    关于Eclipse无法生成class文件的问题
    JavaScript跨域总结与解决办法
  • 原文地址:https://www.cnblogs.com/lcez56jsy/p/10765099.html
Copyright © 2011-2022 走看看