http://poj.org/problem?id=3259
题意大致是N个点, M条正常的边(双向)边权为正,W个虫洞,边权为负,想要
我们判断回路中是否存在一个负圈。学习了bellman-ford算法来求负环,松弛结束后判断是否
存在最短路,不存在则有负环。
#include <stdio.h> #include <string.h> #include <stdlib.h> const int maxn = 1 << 9, inf = 0x3f3f3f3f; int dist[maxn]; int N, M, W, es; struct Edge { int u, v, w; }e[maxn * maxn]; void addedge(int u, int v, int w) { e[es].u = u, e[es].v = v, e[es ++].w = w; } void readgraph() { int u, v, w; es = 0; scanf("%d%d%d", &N, &M, &W); for(int i = 0; i < M; i ++) { scanf("%d%d%d", &u, &v, &w); addedge(u, v, w); addedge(v, u, w); } for(int i = 0; i < W; i ++) { scanf("%d%d%d", &u, &v, &w); addedge(u, v, -w); } } void relax(int es) { int u = e[es].u, v = e[es].v, w = e[es].w; if(dist[v] > dist[u] + w) dist[v] = dist[u] + w; } bool bellman(int src) { for(int i = 1; i < N; i ++) dist[i] = inf; dist[src] = 0; for(int i = 0; i < N - 1; i ++) { for(int j = 0; j < es; j ++) { relax(j); } } for(int i = 0; i < es; i ++) { if(dist[e[i].v] > dist[e[i].u] + e[i].w) return false; } return true; } int main() { int T; scanf("%d", &T); while(T --) { readgraph(); if(!bellman(0)) printf("YES\n"); else printf("NO\n"); } return 0; }
下面就是这个算法的过程:
Bellman-Ford(G,w,s) :boolean //图G ,边集 函数 w ,s为源点
1 for each vertex v ∈ V(G) do //初始化 1阶段
2 d[v] ←+∞
3 d[s] ←0; //1阶段结束
4 for i=1 to |v|-1 do //2阶段开始,双重循环。
5 for each edge(u,v) ∈E(G) do //边集数组要用到,穷举每条边。
6 If d[v]> d[u]+ w(u,v) then //松弛判断
7 d[v]=d[u]+w(u,v) //松弛操作 2阶段结束
8 for each edge(u,v) ∈E(G) do
9 If d[v]> d[u]+ w(u,v) then
10 Exit false
11 Exit true