经典的差分约束问题,对于每一条语句:
P A B X ==> dis[B]-dis[A]==X ==> dis[B]-dis[A]>=X && dis[A]-dis[B]>=X
V A B ==> dis[B]-dis[A]>=1
然后相应的连边即可,最后用spfa判断负环,若无负环,则输出Reliable,反之Unreliable
注意:spfa中的松弛操作应作相应修改,还有spfa无法处理不连通图,可以建立超级源点,或者事先将所有点入队
#include <cstdio> #include <cstring> #include <cstdlib> #include <climits> #include <cmath> #include <iostream> #include <string> #include <vector> #include <set> #include <map> #include <list> #include <queue> #include <stack> #include <deque> #include <algorithm> using namespace std; struct Edge { int from,to; int d; Edge(int from, int to, int d) {this->from=from; this->to=to; this->d=d;} }; const int INF = 0x3f3f3f3f; const int maxn = 1010; int n,m; int dis[maxn]; int cnt[maxn]; bool vis[maxn]; vector<Edge> edges; vector<int> g[maxn]; bool ok; void init() { for (int i=0;i<n;i++) g[i].clear(); edges.clear(); } void addEdge(int from,int to,int d) { edges.push_back(Edge(from,to,d)); int t=edges.size(); g[from].push_back(t-1); } bool spfa(int st) { for (int i=0;i<n;i++) dis[i]=INF; dis[st]=0; for (int i=0;i<n;i++) vis[i]=0; for (int i=0;i<n;i++) cnt[i]=0; queue<int> Q; while (!Q.empty()) Q.pop(); Q.push(st); vis[st]=1; cnt[st]=1; while (!Q.empty()) { int u = Q.front(); for(unsigned int i=0;i<g[u].size();i++) { Edge &e=edges[g[u][i]]; if (dis[e.to]==INF || dis[u]+e.d>dis[e.to]) { dis[e.to]=dis[u]+e.d; if(!vis[e.to]) { Q.push(e.to); vis[e.to]=1; cnt[e.to]++; if(cnt[e.to]>=n) //已经超过n次,出现负环 return 0; } } } Q.pop(); vis[u]=0; } return 1; } int main() { int a,b,c; char ch[3]; while (scanf("%d%d",&n,&m)==2) { n++; ok=1; init(); for (int i=1;i<n;i++) addEdge(0,i,0); while (m--) { scanf("%s",ch); if (ch[0]=='P') { scanf("%d%d%d",&a,&b,&c); addEdge(a,b,c); addEdge(b,a,-c); if (a==b && c!=0) ok=0; } else { scanf("%d%d",&a,&b); addEdge(a,b,1); if (a==b) ok=0; } } if (spfa(0) && ok) puts("Reliable"); else puts("Unreliable"); } return 0; }