本文出自: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;
}