poj3259(spfa)

自己的第一道spfa,纪念一下,顺便转载一下spfa的原理。先po代码:

#include <iostream>
#include <queue>
using namespace std;

const int MAX = 999999;
const int MAXN = 501;

int minimum(int a, int b){
    return a > b ? b : a;
}

int main()
{
    int t;
    cin >> t;
    while (t--){
        int n, m, w;
        cin >> n >> m >> w;
        int field[MAXN];
        bool visited[MAXN];
        int edge[MAXN][MAXN];
        int visitCnt[MAXN];
        memset(field, MAX, sizeof(field));
        memset(edge, MAX, sizeof(edge));
        memset(visited, 0, sizeof(visited));
        memset(visitCnt, 0, sizeof(visitCnt));
        for (int i = 0; i < m; i++){
            int field1, field2, len;
            cin >> field1 >> field2 >> len;
            edge[field1][field2] = minimum(edge[field1][field2], len);
            edge[field2][field1] = minimum(edge[field2][field1], len);
        }
        for (int i = 0; i < w; i++){
            int field1, field2, len;
            cin >> field1 >> field2 >> len;
            edge[field1][field2] = minimum(edge[field1][field2], (-1) * len);
        }
        field[1] = 0;
        queue<int> Q;
        Q.push(1);
        visited[1] = true;
        visitCnt[1] = 1;
        bool flag = false;
        while (!Q.empty()){
            int current = Q.front();
            Q.pop();
            visited[current] = false;
            for (int i = 1; i <= n; i++){
                int tmp = field[current] + edge[current][i];
                if (tmp < field[i]){
                    field[i] = tmp;
                    if (!visited[i]){
                        Q.push(i);
                        visited[i] = true;
                        visitCnt[i]++;
                        if (visitCnt[i] > n){
                            flag = true;
                            break;
                        }
                    }
                }
            }
            if (flag)
                break;
        }
        if (flag){
            cout << "YES" << endl;
        }
        else{
            cout << "NO" << endl;
        }
    }
    return 0;
}

以下内容转自http://www.cnblogs.com/zgmf_x20a/archive/2008/12/18/1357737.html

求最短路径的算法有许多种,除了排序外,恐怕是OI界中解决同一类问题算法最多的了。最熟悉的无疑是Dijkstra,接着是Bellman-Ford,它们都可以求出由一个源点向其他各点的最短路径;如果我们想要求出每一对顶点之间的最短路径的话,还可以用Floyd-Warshall。

SPFA是这篇日志要写的一种算法,它的性能非常好,代码实现也并不复杂。特别是当图的规模大,用邻接矩阵存不下的时候,用SPFA则可以很方便地面对临接表。每个人都写过广搜,SPFA的实现和广搜非常相似。

如何求得最短路径的长度值?

首先说明,SPFA是一种单源最短路径算法,所以以下所说的“某点的最短路径长度”,指的是“某点到源点的最短路径长度”。

我们记源点为S,由源点到达点i的“当前最短路径”为D[i],开始时将所有D[i]初始化为无穷大,D[S]则初始化为0。算法所要做的,就是在运行过程中,不断尝试减小D[]数组的元素,最终将其中每一个元素减小到实际的最短路径。

过程中,我们要维护一个队列,开始时将源点置于队首,然后反复进行这样的操作,直到队列为空:

(1)从队首取出一个结点u,扫描所有由u结点可以一步到达的结点,具体的扫描过程,随存储方式的不同而不同;

(2)一旦发现有这样一个结点,记为v,满足D[v] > D[u] + w(u, v),则将D[v]的值减小,减小到和D[u] + w(u, v)相等。其中,w(u, v)为图中的边u-v的长度,由于u-v必相邻,所以这个长度一定已知(不然我们得到的也不叫一个完整的图);这种操作叫做松弛。

松弛操作的原理是著名的定理:“三角形两边之和大于第三边”,在信息学中我们叫它三角不等式。所谓对i,j进行松弛,就是判定是否d[j]>d[i]+w[i,j],如果该式成立则将d[j]减小到d[i]+w[i,j],否则不动。

(3)上一步中,我们认为我们“改进了”结点v的最短路径,结点v的当前路径长度D[v]相比于以前减小了一些,于是,与v相连的一些结点的路径长度可能会相应地减小。注意,是可能,而不是一定。但即使如此,我们仍然要将v加入到队列中等待处理,以保证这些结点的路径值在算法结束时被降至最优。当然,如果连接至v的边较多,算法运行中,结点v的路径长度可能会多次被改进,如果我们因此而将v加入队列多次,后续的工作无疑是冗余的。这样,就需要我们维护一个bool数组Inqueue[],来记录每一个结点是否已经在队列中。我们仅将尚未加入队列的点加入队列。

算法能否结束?

对于不存在负权回路的图来说,上述算法是一定会结束的。因为算法在反复优化各个最短路径长度,总有一个时刻会进入“无法再优化”的局面,此时一旦队列读空,算法就结束了。然而,如果图中存在一条权值为负的回路,就糟糕了,算法会在其上反复运行,通过“绕圈”来无休止地试图减小某些相关点的最短路径值。假如我们不能保证图中没有负权回路,一种“结束条件”是必要的。这种结束条件是什么呢?

思考Bellman-Ford算法,它是如何结束的?显然,最朴素的Bellman-Ford算法不管循环过程中发生了什么,一概要循环|V|-1遍才肯结束。凭直觉我们可以感到,SPFA算法“更聪明一些”,就是说我们可以猜测,假如在SPFA中,一个点进入队列——或者说一个点被处理——超过了|V|次,那么就可以断定图中存在负权回路了。

最短路径本身怎么输出?

在一幅图中,我们仅仅知道结点A到结点E的最短路径长度是73,有时候意义不大。这附图如果是地图的模型的话,在算出最短路径长度后,我们总要说明“怎么走”才算真正解决了问题。如何在计算过程中记录下来最短路径是怎么走的,并在最后将它输出呢?

Path[]数组,Path[i]表示从S到i的最短路径中,结点i之前的结点的编号。注意,是“之前”,不是“之后”。最短路径算法的核心思想成为“松弛”,原理是三角形不等式,方法是上文已经提及的。我们只需要在借助结点u对结点v进行松弛的同时,标记下Path[v] = u,记录的工作就完成了。

输出时可能会遇到一点难处,我们记的是每个点“前面的”点是什么,输出却要从最前面往最后面输,这不好办。其实很好办,见如下递归方法:

void PrintPath(int k){
    if( Path[k] ) PrintPath(Path[k]);
    fout<<k<<‘ ‘;
}

时间: 2024-10-20 03:29:34

poj3259(spfa)的相关文章

poj3259(Wormholes)

题目大意: 一个农夫在农场发现了许多奇怪的虫洞,这些虫洞是单向的,已知N个农场,M条正常的路径,W条虫洞,虫洞可以使时间倒流,农主通过正常的路径花费一定的时间,这个路径是双向的, 通过虫洞的路径可以使时间倒流,农主是狂热的旅行者,他的目的是通过正常路径和虫洞,能否回到最初的起点的时刻! 解题思路: bellman_ford算法,看是否有负权回路,有负权回路说明农主到达最初出发的农场"1"的权值小于0,也就意味着农主能通过虫洞的时光倒流回到最初出发农场的那个时刻,注意单向边和双向边,和数

HDU 2680Choose the best route (SPFA)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2680 百度之星编程大赛--您报名了吗? 杭电ACM 2014暑期集训队--选拔安排~ Choose the best route Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis

poj 1860 Currency Exchange(SPFA)

题目链接:http://poj.org/problem?id=1860 Description Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and performs exchange operations only with these currencies. There can b

模板C++ 03图论算法 1最短路之单源最短路(SPFA)

3.1最短路之单源最短路(SPFA) 松弛:常听人说松弛,一直不懂,后来明白其实就是更新某点到源点最短距离. 邻接表:表示与一个点联通的所有路. 如果从一个点沿着某条路径出发,又回到了自己,而且所经过的边上的权和小于0, 就说这条路是一个负权回路. 回归正题,SPFA是bellman-ford的一种改进算法,由1994年西安交通大学段凡丁提出.它无法处理带有负环的图,判断方法:如果某个点进入队列的次数超过N次则存在负环. SPFA的两种写法,bfs和dfs,bfs判别负环不稳定,相当于限深度搜索

hiho一下 第二十五周(SPFA)

时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的晚上,小Hi和小Ho在吃过晚饭之后,来到了一个巨大的鬼屋! 鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些道路连通,两个地点之间可能有多条道路连通,但是并不存在一条两端都是同一个地点的道路. 不过这个鬼屋虽然很大,但是其中的道路并不算多,所以小Hi还是希望能够知道从入口到出口的最短距离是多少? 提示:Super Programming Festival Algorithm. 输入 每个测试点

hihoCoder - 1093 - 最短路径&#183;三:SPFA算法 (SPFA)

#1093 : 最短路径·三:SPFA算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的晚上,小Hi和小Ho在吃过晚饭之后,来到了一个巨大的鬼屋! 鬼屋中一共有N个地点,分别编号为1..N,这N个地点之间互相有一些道路连通,两个地点之间可能有多条道路连通,但是并不存在一条两端都是同一个地点的道路. 不过这个鬼屋虽然很大,但是其中的道路并不算多,所以小Hi还是希望能够知道从入口到出口的最短距离是多少? 提示:Super Programming Festiv

zoj 3103 Cliff Climbing(spfa )

Cliff Climbing Time Limit: 10 Seconds      Memory Limit: 32768 KB At 17:00, special agent Jack starts to escape from the enemy camp. There is a cliff in between the camp and the nearest safety zone. Jack has to climb the almost vertical cliff by step

codevs 1021 玛丽卡(spfa)

题目描述 Description 麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复. 因为她和他们不住在同一个城市,因此她开始准备她的长途旅行. 在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间. 麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路.无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市. 玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车.麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需

【模板】负环(spfa)

洛谷——P3385 [模板]负环 题目描述 暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索 输入输出格式 输入格式: 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个顶点,M条边 接下来M行,每行三个整数a b w,表示a->b有一条权值为w的边(若w<0则为单向,否则双向) 输出格式: 共T行.对于每组数据,存在负环则输出一行"YE5"(不含引号),否则输出一行"N0"(不含引号). 输入输出样例