题目:
Time Limit: 2000MS | Memory Limit: 65536K | |
Total 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..N, M (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 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2.. M+1 of each farm: Three space-separated numbers ( S, E, T) 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 ( S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.
Output
Sample Input
2 3 3 1 1 2 2 1 3 4 2 3 1 3 1 3 3 2 1 1 2 3 2 3 4 3 1 8
Sample Output
NO YES
链接: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来解决这个问题。
#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;