题目链接: http://poj.org/problem?id=1860
题解:
两种情况YES,一种是存在正权回路;
一种是求最长路后,实现了增值,也是YES;
用spfa来判断是否存在正权回路,其实spfa是可以用来判断是否存在回路的,不管是正权还是负权,只不过它们松弛的条件不同,正权的话,我们是往dis[]权值增大的方向松弛,负权的话,我们是往dis[]权值减少的方向松弛,然后判断是否存在回路只要看有没有一点入队列的次数大于n就行了用spfa来判断是否存在正权回路,其实spfa是可以用来判断是否存在回路的,不管是正权还是负权,只不过它们松弛的条件不同,正权的话,我们是往dis[]权值增大的
如果存在一个环(从某个点出发又回到自己的路径),而且这个环上所有权值之和是负数,那这就是一个负权环,也叫负权回路;同理正权回路;
#include <iostream> #include <cstdio> #include <cstring> #include <stdlib.h> #include <math.h> #include <queue> #include <algorithm> using namespace std; #define N 210 #define INF 0xfffffff double dist[N], V; int cnt, Head[N], num[N], vis[N]; int n, m, s; struct Edge { int v, next; double r, c; }e[N]; void Add(int u, int v, double r, double c) { e[cnt].v = v; e[cnt].r = r; e[cnt].c = c; e[cnt].next = Head[u]; Head[u] = cnt++; } bool spfa()///spfa模板; { memset(vis, 0, sizeof(vis)); memset(num, 0, sizeof(num)); queue<int>Q; vis[s] = 1; dist[s] = V; Q.push(s); num[s]++; while(Q.size()) { int p=Q.front(); Q.pop(); vis[p] = 0; for(int i=Head[p]; i!=-1; i=e[i].next) { int q = e[i].v; if(dist[q] < (dist[p] - e[i].c) * e[i].r)///注意松弛的变化; { dist[q] = (dist[p] - e[i].c) * e[i].r; if(!vis[q]) { vis[q] = 1; Q.push(q); num[q] ++; if(num[q]>n) return true;///存在正权回路; } } } } if(dist[s]>V)///最长路后,实现了增值; return true; return false; } int main() { int a, b; double rab, rba, cab, cba; while(scanf("%d%d%d%lf", &n, &m, &s, &V)!=EOF) { cnt = 0; memset(Head, -1, sizeof(Head)); memset(dist, 0, sizeof(dist)); for(int i=1; i<=m; i++) { scanf("%d%d%lf%lf%lf%lf", &a, &b, &rab, &cab, &rba, &cba); Add(a, b, rab, cab); Add(b, a, rba, cba); } if( spfa() ) printf("YES "); else printf("NO "); } return 0; }