http://poj.org/problem?id=2983
题意:给出M条信息,判断这些信息的正确性。(1)V A B :表示A,B之间的距离>=1; (2)P A B X :表示A B之间的距离为x。
思路:dis[i]表示i到原点的距离,由(1)知 dis[A]<=dis[B]-1 即B->A之间有一条边,权值为-1;由(2)知: dis[A]<=dis[B]-x && dis[B] <= dis[A]+x,即A->B的权值为-x,B->A的权值为x。增加一个超级源点,与所有的点相连且权值为0.建图,spfa判断是否有负环(即判断进站次数,若大于点数则存在负环)。若存在负环则信息为假,否则为真。
1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 using namespace std; 5 const int N=1000010; 6 const int INF=1<<28; 7 int head[1010],vis[1010]; 8 int dis[N],num[1010]; 9 int cnt,n; 10 11 struct node 12 { 13 int u,v,w; 14 int next; 15 } edge[N]; 16 void init() 17 { 18 cnt = 0; 19 memset(head,-1,sizeof(head)); 20 memset(vis,0,sizeof(vis)); 21 memset(num,0,sizeof(num)); 22 } 23 void add(int u,int v,int w) 24 { 25 edge[cnt].u = u; 26 edge[cnt].v = v; 27 edge[cnt].w = w; 28 edge[cnt].next = head[u]; 29 head[u] = cnt++; 30 } 31 int spfa() 32 { 33 queue<int>q; 34 for (int i = 0; i <= n; i ++) 35 dis[i] = INF; 36 dis[0] = 0; 37 q.push(0); 38 vis[0] = 1; 39 while(!q.empty()) 40 { 41 int u = q.front(); 42 vis[u] = 0; 43 q.pop(); 44 for (int j = head[u]; j!=-1; j=edge[j].next) 45 { 46 int v = edge[j].v; 47 int w = edge[j].w; 48 if (dis[v] > dis[u]+w) 49 { 50 dis[v] = dis[u]+w; 51 if (!vis[v]) 52 { 53 q.push(v); 54 vis[v] = 1; 55 ++num[v]; 56 if (num[v] > n) 57 return 0; 58 } 59 } 60 } 61 } 62 return 1; 63 } 64 int main() 65 { 66 int m,u,v,w; 67 char s[3]; 68 while(~scanf("%d%d",&n,&m)) 69 { 70 init(); 71 for (int i = 0; i <= n; i++) 72 add(0,i,0); 73 for (int i = 0; i < m; i++) 74 { 75 scanf("%s",s); 76 if (s[0]=='P') 77 { 78 scanf("%d %d %d",&u,&v,&w); 79 add(u,v,w); 80 add(v,u,-w); 81 } 82 if (s[0]=='V') 83 { 84 scanf("%d %d",&u,&v); 85 add(v,u,-1); 86 } 87 } 88 if (spfa()) 89 printf("Reliable "); 90 else 91 printf("Unreliable "); 92 } 93 return 0; 94 }