本文出自:http://blog.csdn.net/svitter
原题:http://poj.org/problem?id=3259
题意:最基础的Bellman-Ford题目,寻找负环.告诉你有几个村庄,在村庄中有通路,通路走过去花费时间,通路是双向的,走虫洞可以使时间倒退,即负边.但是负边是单向的.
总结写在最前面:
Bellman-Ford算法最关键就在于判断有无负环;
Bellman-Ford算法刚刚自学,还不是很明白.一开始觉得使用邻接矩阵即可,想松弛n-1次以后看看还能不能再松弛,如果可以松弛说明有负环.一开始不过,心中甚是郁闷--(手懒不想写结构体..)实在无奈用了邻接表的形式(这才发现多写不了多少东西,输入的时候多加注意即可..)依然WA--这才好好看看了看..
问题在于:邻接表是对边处理,邻接矩阵则是对点处理.
在进行松弛操作的时候边的个数搞错了-=应该是m*2(双向边)+w(虫洞边)这才是最后的结果..也明白邻接表的速度要比邻接矩阵快的多..o(n^2)和O(n^3)明显不是一个级别--因此稀疏图还是要用邻接表.为了测试一下想法重写了邻接矩阵的算法,果然Time limit exception...不死心的我剪了剪枝还交了两次呵呵果然==再一次..
终于大彻大悟写了AC代码:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define INF 0x1f1f1f1f int n, m ,w, e; int res[505]; struct Edge { int u; int v; int w; }; Edge edge[6000]; bool bellman(int n, int m, int src) { memset(res, 0x1f, sizeof(res)); res[src] = 0; for(int i = 0; i < n; i++) for(int j = 0; j < m; j++) { e = res[edge[j].u] + edge[j].w; res[edge[j].v] = res[edge[j].v] < e? res[edge[j].v] : e; } for(int i = 0; i < n; i++) for(int j = 0; j < m; j++) { if(res[edge[j].v] > res[edge[j].u] + edge[j].w) return 1; } return 0; } void ace() { //work point; int i, j, k; //case int f; //num int s, e, c; scanf("%d", &f); while(f--) { scanf("%d%d%d", &n, &m, &w); // for(i = 0; i < m; i++) { scanf("%d%d%d", &s, &e, &c); //Two fields might be connected by more than one path. edge[i].u = s; edge[i].v = e; edge[i].w = c; edge[i + m].v = s; edge[i + m].u = e; edge[i + m].w = c; } //wormhole w += m * 2; for(i = m * 2; i < w; i++) { scanf("%d%d%d", &s, &e, &c); edge[i].u = s; edge[i].v = e; edge[i].w = -c; } m = w;//边数更改为w,包含虫洞,双向边. if(bellman(n, m, 1)) printf("YES\n"); else printf("NO\n"); } } int main() { ace(); return 0; }
POJ3259 Wormholes (Bellman-Ford最短路径算法)
原文地址:http://blog.csdn.net/svitter/article/details/24718111