Bellman-ford算法和详解
http://www.wutianqi.com/blog/1912.html
poj3295
t译文:农夫约翰在探索他的许多农场,发现了一些惊人的虫洞。虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的N(1≤N≤500)个农场被编号为1..N,之间有M(1≤M≤2500)条路径,W(1≤W≤200)个虫洞。作为一个狂热的时间旅行FJ的爱好者,他要做到以下几点:开始在一个区域,通过一些路径和虫洞旅行,他要回到最开时出发的那个区域出发前的时间。也许他就能遇到自己了:)。为了帮助FJ找出这是否是可以或不可以,他会为你提供F个农场的完整的映射到(1≤F≤5)。所有的路径所花时间都不大于10000秒,所有的虫洞都不大于万秒的时间回溯。
输入
第1行:一个整数F表示接下来会有F个农场说明。
每个农场第一行:分别是三个空格隔开的整数:N,M和W
第2行到M+1行:三个空格分开的数字(S,E,T)描述,分别为:需要T秒走过S和E之间的双向路径。两个区域可能由一个以上的路径来连接。
第M +2到M+ W+1行:三个空格分开的数字(S,E,T)描述虫洞,描述单向路径,S到E且回溯T秒。
输出
F行,每行代表一个农场
每个农场单独的一行,” YES”表示能满足要求,”NO”表示不能满足要求。
NO
YES
#include <iostream>
using namespace std;
typedef struct Edge{
int u;
int v;
int weight;
}Edge;
Edge edge[6000];
int dis[501] = {};
const int inf = 0x3f3f3f3f;
int N, M, W;//N, nodenum; M edgenum; W negtive edgenum
bool bellman() {
for (int i = 0; i < 501; ++i)
dis[i] = inf;
dis[1] = 0;
//N-1次松弛操作
for (int i = 1; i <= N - 1; ++i) {
//遍历所有的边,对dis进行更新
for (int j = 1; j <= 2*M + W; ++j) {
if (dis[edge[j].v] > dis[edge[j].u] + edge[j].weight) {
dis[edge[j].v] = dis[edge[j].u] + edge[j].weight;
}
}
}
//如果v顶点的dis[v]值大于另一个顶点经边(u, v)得到的值{dis[u]+weight(u, v)}
//违反了dis的定义,说明存在负圈
for (int i = 1; i <= 2*M; ++i) {
if (dis[edge[i].v] > dis[edge[i].u] + edge[i].weight)
return true;
}
return false;
}
int main() {
int F;
cin >> F;
while (F--) {
cin >> N >> M >> W;
int index = 1;
int a, b, c;
for (int i = 1; i <= M; ++i) {
cin >> a >> b >> c;
edge[index].u = a;
edge[index].v = b;
edge[index++].weight = c;
edge[index].u = b;
edge[index].v = a;
edge[index++].weight = c;
}
for (int i = M + 1; i <= M + W; ++i) {
cin >> a >> b >> c;
edge[index].u = a;
edge[index].v = b;
edge[index++].weight = -c;
}
cout << (bellman() ? "YES\n" : "NO\n");
}
return 0;
}