zoukankan      html  css  js  c++  java
  • 最短路最新心得

    如果,上面的图,如果用dij算法,那么dist[4] = 4,  是得不到正确的结果的, 这个因为dist[3]先被确定是最小,然后用来更新dist[4]

    但是存在负权,使得dist[3]更小,但是我们已经把结点3标记为不可用了(vis[3] = true), 所以存在错误

    如何使得使得结点3可用呢? 我们把判断的条件给改一下,如果结点u出队列之后,其权值为dist[u] 来得小, 那么就可以用它来更新其他的定点

    这样子,每个结点都可以多次入队列, 使得dij可以处理负权

     1 int dij(int x, int y, int n)
     2 {
     3     for (int i = 1; i <= n; ++i)
     4         dist[i] = INF;
     5     priority_queue<Edge> q;
     6     Edge cur, tmp;
     7     cur.dist = dist[x] = 0;
     8     cur.v = x;
     9     q.push(cur);
    10     while (!q.empty())
    11     {
    12         cur = q.top(); q.pop();
    13         int u = cur.v;
    14         if (dist[u] < cur.dist)//如果cur.dist < dist[u], 那么可以继续更新其他顶点, 代替了条件vis[u]
    15             continue;
    16         for (int i = 0; i < g[u].size(); ++i)
    17         {
    18             int v = g[u][i].v;
    19             if (dist[v] > dist[u] + g[u][i].dist)
    20             {
    21                 tmp.dist = dist[v] = dist[u]+ g[u][i].dist;
    22                 tmp.v = v;
    23                 q.push(tmp);
    24             }
    25         }
    26     }
    27     return dist[y];
    28 }

    bellaman__ford算法的无用操作

    void relax(int u, int v,double weight)
    {
        if(dist[v] > dist[u] + weight)
            dist[v] = dist[u] + weight;
    }
    bool bellman_ford(int n, int m)
    {
        int i,j;
        for(i=0; i<n-1; ++i)//n-1循环
            for(j=0; j<m; ++j)//枚举所有的边去松弛最短路径
            {
                relax(g[j].u,g[j].v,g[j].weight);
            }
        bool flag = false;
        for(i=0; i<m; ++i)
            if(dist[g[i].v] > dist[g[i].u] + g[i].weight)
            {
                flag = true;
                break;
            }
        return flag;
    }

    如上述代码所示, 我们枚举每条边, 看看能不能松弛最短路径, 但这么做,其实做了很多的无用功, 比如说如果 dist[g[j]] 没有被松弛过或者松弛不成功,

    那么relax(g[j].u,g[j].v,g[j].weight) 做的就是无用功

    对于这个, 我们可以用队列来优化bellman算法, (上交的大神发明的,时间复杂度是O(ke),k是常数,虽然后来被证实它证明的k是常数是错误的)

    如果结点u被更新过了, 那么才可以用它来更新它所指向的定点 

    int spfa(int x, int y, int n)
    {
        for (int i = 1; i <= n; ++i)
            dist[i] = INF;
        queue<int> q;
        q.push(x);
        dist[x] = 0;
        while (!q.empty())
        {
            int u = q.front(); q.pop();
            vis[u] = false;
            for (int i = 0; i < g[u].size(); ++i)
            {
                int v = g[u][i].v;
                if (dist[v] > dist[u] + g[u][i].dist)
                {
                    dist[v] = dist[u] + g[u][i].dist;//能更新就更新
                    if (!vis[v])//如果结点在队里里面,就不用重复入队了
                    {
                        q.push(v);
                        vis[v] = true;
                    }
                }
            }
        }
        return dist[y];
    }
  • 相关阅读:
    Bootstrap历练实例:带有下拉菜单的标签和胶囊导航
    python学习网址
    /mnt/sdcard 是什么东西
    tornado中文教程
    ssh免密码登录远程服务器(不采用securecrt登录)
    接口测试博客
    [python学习篇] [os模块] [2]删除文件夹
    解压文件夹python
    adb pull 文件夹的时候注意
    [uiautomator篇][python调用java][1]应用下载的插件需要很长时间问题解决
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4646413.html
Copyright © 2011-2022 走看看