题目链接:kuangbin带你飞 专题四 最短路练习 F – Wormholes
题意
农场主拥有很多农场,在这些农场之间有很多条路,以及单向的虫洞,每条路走完会花费一定的时间,而冲动可以回到之前的时间,问农场主是否可以通过特定的路径看到出发前的自己?(也就是回到自己出发时间前的出发点)
思路
将农场看做点,路和虫洞看做边,那么显然虫洞是负权边,这样题目就转化为求给定图中是否有负环的问题了。
Bellman-Ford和SPFA都可以进行负环的判断,因为这两个算法以前都没用过,索性就都写了一下,慢慢熟练。
SPFA是对Bellman-Ford进行队列优化的改进版,但提交后反而比Bellman-Ford慢,这点挺奇怪的。
不知道是数据的原因,还是什么?
代码
Bellman-Ford
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 509;
const int MAX = 0x3f3f3f3f;
struct Edge
{
int u, v, r;
}edge[N*N+200];
int d[N];
bool Bellman_Ford(int n, int e, int src)
{
for(int i=1; i<=n; i++)
d[i] = MAX;
d[src] = 0;
while(d[src] >= 0)
{
bool flag = true;
for(int i=0; i<e; i++)
{
int u = edge[i].u;
int v = edge[i].v;
int to = d[u] + edge[i].r;
if(d[v] > to)
{
d[v] = to;
flag = false;
}
}
if(flag)
return d[src] < 0;
}
return 1;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n, m, w;
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);
edge[i].u = a;
edge[i].v = b;
edge[i].r = c;
edge[i+m].u = b;
edge[i+m].v = a;
edge[i+m].r = c;
}
for(int i=0; i<w; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
edge[2*m+i].u = a;
edge[2*m+i].v = b;
edge[2*m+i].r = -c;
}
if(Bellman_Ford(n, m*2+w, 1))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
SPFA
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 509;
const int MAX = 0x3f3f3f3f;
struct Edge
{
int u, v, r, next;
}edge[N*N+200];
int d[N];
int h[N];
bool vis[N];
int cnt[N];
bool spfa(int n)
{
memset(vis, 0, sizeof(vis));
memset(cnt, 0, sizeof(cnt));
for(int i=1; i<=n; i++)
d[i] = MAX;
d[1] = 0;
vis[1] = 1;
cnt[1]++;
queue<int> q;
q.push(1);
while(!q.empty())
{
int x = q.front();
vis[x] = 0;
q.pop();
for(int i = h[x]; i!=-1; i = edge[i].next)
{
int v = edge[i].v;
int to = edge[i].r + d[edge[i].u];
if(d[v] > to)
{
d[v] = to;
if(!vis[v])
{
vis[v] = 1;
q.push(v);
if(++cnt[v] > n)
return 1;
}
}
}
}
return 0;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n, m, w;
memset(h, -1, sizeof(h));
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);
edge[i].next = h[a];
edge[i].u = a;
edge[i].v = b;
edge[i].r = c;
h[a] = i;
edge[i+m].next = h[b];
edge[i+m].u = b;
edge[i+m].v = a;
edge[i+m].r = c;
h[b] = i+m;
}
for(int i=0; i<w; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
edge[2*m+i].next = h[a];
edge[2*m+i].u = a;
edge[2*m+i].v = b;
edge[2*m+i].r = -c;
h[a] = 2*m+i;
}
if(spfa(n))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}