bellman ford算法

//bellman ford算法
//今天我们来说说最小路径得最后一个算法也是一个重要得算法了
//当权值为负数得时候DIJKSTRA用不是用不上得
//bellman ford算法可以计算权值为负数的最小路径 但是也是不能计算有权值为负数的环
//现在这里普及一个思路 环一共有三种 第一种是零环 另一个是正环 再一个是负环
//在最小路径上零环和正环都是可以忽略的 但是如果是负环的话 就没有最小路径的存在
//综上所述就是意味着最小路径上是没有环的存在 那么就以为着只需要走n-1个节点就可以知道有没有结果 如果超过的话就意味着没有最小路径 存在负环
for(int i=0;i<n-1;i++)d[i]=INF;
d[0]=0;
for(int k=0;k<n-1;k++)
    for(int i=0;i<m;i++)
{
    int x=u[i],y=v[i];
    if(d[x]<INF) d[y]=min(d[y],d[x]+w[i]);
}


typedef struct Edge
{
    int from,to,dist;
}Edge;
struct BellmanFord{
int n,m;
vector<Edge>edges;
vector<int>G[maxn];
bool inq[maxn];//是否在队列里
int d[maxn];//s到各个点的最小距离
int p[maxn];//最短路径上的一条弧
int cnt[maxn];//进栈的次数
void init(int n)
{
    this->n=n;
    for(int i=0;i<n;i++) G[i].clear();
    edges.clear();
}
void AddEdge(int from,int to,int dis)
{
    edges.push_back((Edge){from,to,dis});
    m=edges.size();
    G[from].push_back(m-1);
}
bool negativeCycle(int s)
{
    queue<int>Q;
    memset(inq,0,sizeof(inq));
    memset(cnt,0,sizeof(cnt));
    for(int i=0;i<n;i++) d[i]=INF;
    d[s]=0;
    inq[s]=true;
    Q.push(s);
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        inq[u]=false;
        for(int i=0;i<G[u].size();i++)
        {
            Edge& e=edges[G[u][i]];
            if(d[u]<INF&&d[u]+e.dist<d[e.to])//这里感觉加d[u]<INF并没有多大的意义 因为这里的D【u】肯定都是有值的
            {
              d[e.to]=d[u]+e.dist;
              p[e.to]=G[u][i];//G是记录第几条边
              if(!inq[e.to])
              {
                  Q.push(e.to);
                  inq[e.to]=true;
                  if(++cnt[e.to]>n) return false;
              }
            }
        }
    }
}
};
//在这里有必要说一下if(!inq[e.to])  我觉得这个算法和SPFA有点相似  也就是说和BFS有点相似 把符合条件相近的点入队列 
//但是有有一点区别就是同一个点可以进入多次 但是进入的次数大于n的话就证明这个存在负数环 return false 
//原本在队列的节点只需要改变一下自身的最短路径信息就可以了 不用再进栈一次 因为栈里面有 那么迟早都会修改因为自身的改变而导致相关联节点改变的情况
//总的来说就是 看有没有负数权值 如果没有就是用dijkstra 如果有负权值的话就可以使用SPFA  但是很容别别人卡数据KE(负环也是不行的) 最后就是使用bellman ford算法

猜你喜欢

转载自blog.csdn.net/hnust_lizeming/article/details/76221090