POJ 3259 Wormholes

来源:互联网 发布:mysql error code 1022 编辑:程序博客网 时间:2024/06/05 11:20

题目:

Wormholes
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 27825 Accepted: 10012

Description

While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ's farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..NM (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.

As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself :) .

To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.

Input

Line 1: A single integer, FF farm descriptions follow. 
Line 1 of each farm: Three space-separated integers respectively: NM, and W 
Lines 2..M+1 of each farm: Three space-separated numbers (SET) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected by more than one path. 
Lines M+2..M+W+1 of each farm: Three space-separated numbers (SET) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.

Output

Lines 1..F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).

Sample Input

23 3 11 2 21 3 42 3 13 1 33 2 11 2 32 3 43 1 8

Sample Output

NOYES


链接:http://poj.org/problem?id=3259


题目大意:

给你n个点,有m条路是无向的(权值为正),w条路是有向的(权值为负),判断是否存在负权回路。


解题思路:

这是一个负权回路的判断问题,我们可以用Bellman-Ford算法开解决。Bellmall-Ford的基本思想是:

   // 该实现读入边和节点的列表,并向两个数组(distance和predecessor)中写入最短路径信息   // 步骤1:初始化图   for each vertex v in vertices:       if v is source then distance[v] := 0       else distance[v] := infinity       predecessor[v] := null   // 步骤2:重复对每一条边进行松弛操作   for i from 1 to size(vertices)-1:       for each edge (u, v) with weight w in edges:           if distance[u] + w < distance[v]:               distance[v] := distance[u] + w               predecessor[v] := u   // 步骤3:检查负权环   for each edge (u, v) with weight w in edges:       if distance[u] + w < distance[v]:           error "图包含了负权环"

我们也可以用spfa来解决这个问题。


方法1代码:

#include <iostream>#include <cstdio>#include <cstring>#include <limits.h>using namespace std;const int MAXN = 510;struct Eage{int s, e, v;};Eage eage[5200];int n, m, w, cnt, dis[MAXN];int BellmanFord(){for(int i = 1; i <= n; i++){dis[i] = INT_MAX;}dis[1] = 0;for(int i = 1; i < n; i++){for(int j = 0; j < cnt; j++){if(dis[eage[j].s] < dis[eage[j].e] - eage[j].v){dis[eage[j].e] = dis[eage[j].s] + eage[j].v;}}}for(int i = 0; i < cnt; i++){if(dis[eage[i].s] < dis[eage[i].e] - eage[i].v){return 1;}}return 0;}int main(){int f;scanf("%d", &f);while(f--){cnt = 0;memset(eage, 0, sizeof(eage));memset(dis, 0, sizeof(dis));scanf("%d%d%d", &n, &m, &w);for(int i = 0; i < m; i++){int a, b, c;scanf("%d%d%d", &a, &b, &c);eage[cnt].s   = a;eage[cnt].e   = b;eage[cnt++].v = c;eage[cnt].s   = b;eage[cnt].e   = a;eage[cnt++].v = c;}for(int i = 0; i < w; i++){int a, b, c;scanf("%d%d%d", &a, &b, &c);eage[cnt].s   = a;eage[cnt].e   = b;eage[cnt++].v = -c;}printf("%s\n", BellmanFord() ? "YES" : "NO");}return 0;}

方法2代码:

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <limits.h>using namespace std;const int MAXN = 510;struct Eage{int e, v;};vector<Eage> eage[MAXN];int n, m, w, dis[MAXN];int spfa(){int num[MAXN], vis[MAXN];memset(num, 0, sizeof(num));memset(vis, 0, sizeof(vis));dis[1] = 0; vis[1] = num[1] = 1;queue<int> q; q.push(1);while(!q.empty()){int x = q.front();q.pop(); vis[x] = 0;int size = eage[x].size();for(int i = 0; i < size; i++){int e = eage[x][i].e, v = eage[x][i].v;if(dis[x] + v < dis[e]){dis[e] = dis[x] + v;if(!vis[e]){vis[e] = 1;num[e]++;if(num[e] >= n) return 1;q.push(e);}}}}return 0;}int main(){int f;scanf("%d", &f);while(f--){Eage tmp;scanf("%d%d%d", &n, &m, &w);for(int i = 1; i <= n; i++){eage[i].clear();dis[i] = INT_MAX;}while(m--){int a, b, c;scanf("%d%d%d", &a, &b, &c);tmp.e = b, tmp.v = c;eage[a].push_back(tmp);tmp.e = a, tmp.v = c;eage[b].push_back(tmp);}while(w--){int a, b, c;scanf("%d%d%d", &a, &b, &c);tmp.e = b, tmp.v = -c;eage[a].push_back(tmp);}printf("%s\n", spfa() ? "YES" : "NO");}return 0;}


或者:

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <limits.h>using namespace std;const int MAXN = 510;struct Eage{int e, v;};vector<Eage> eage[MAXN];int n, m, w, dis[MAXN];int spfa(){int num[MAXN], vis[MAXN];memset(num, 0, sizeof(num));memset(vis, 0, sizeof(vis));dis[1] = 0; vis[1] = num[1] = 1;queue<int> q; q.push(1);while(!q.empty()){int x = q.front();q.pop(); vis[x] = 0;for(vector<Eage>::iterator it = eage[x].begin(); it != eage[x].end(); it++){if(dis[x] + it->v < dis[it->e]){dis[it->e] = dis[x] + it->v;if(!vis[it->e]){vis[it->e] = 1;q.push(it->e);num[it->e]++;if(num[it->e] >= n) return 1;}}}}return 0;}int main(){int f;scanf("%d", &f);while(f--){Eage tmp;scanf("%d%d%d", &n, &m, &w);for(int i = 1; i <= n; i++){eage[i].clear();dis[i] = INT_MAX;}while(m--){int a, b, c;scanf("%d%d%d", &a, &b, &c);tmp.e = b, tmp.v = c;eage[a].push_back(tmp);tmp.e = a, tmp.v = c;eage[b].push_back(tmp);}while(w--){int a, b, c;scanf("%d%d%d", &a, &b, &c);tmp.e = b, tmp.v = -c;eage[a].push_back(tmp);}printf("%s\n", spfa() ? "YES" : "NO");}return 0;}


方法2注意点:

1.如果,dis数组初始化为无穷大,spfa函数里 的判断条件要这么写:if(dis[x] + v < dis[e]),而不能写成if(dis[x] < dis[e]  -  v),因为v可以是负值,可能导致dis[e] - v溢出,以致于结果判断出错(巨坑,因为这个问题,我wa了20+次,简直无语),或者说,如果要用if(dis[x] < dis[e]  -  v)的话,可以把无穷大设的小一点也行

2.入队次数大于n时形成负权回路,if(num[e] >= n) return 1;


0 0