Description
John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。John的每个农场有M条小路(无向边)连接着N (从1..N标号)块地,并有W个虫洞。其中1<=N<=500,1<=M<=2500,1<=W<=200。 现在John想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。 John将向你提供F(1<=F<=5)个农场的地图。没有小路会耗费你超过10000秒的时间,当然也没有虫洞回帮你回到超过10000秒以前。
Input
- Line 1: 一个整数 F, 表示农场个数。
- Line 1 of each farm: 三个整数 N, M, W。
- Lines 2..M+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条用时T秒的小路。
- Lines M+2..M+W+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地中间有一条可以使John到达T秒前的虫洞。
Output
- Lines 1..F: 如果John能在这个农场实现他的目标,输出”YES”,否则输出”NO”。
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
想说的话
这是我第二次写spfa 果断放弃了正常推队列的写法
写成了dfs
一开始空间巨大 140ms
然后空间缩小 28ms
加上fread之后8ms霸榜
这个题想回到过去 所以我们需要的就是判断负环
用前向星存图
struct edge
{
int to,len;
}e[M];
int head[N],dis[N],nxxt[M];
inline void addedge(int u,int v,int w)
{
tot++;
e[tot].to=v;
nxxt[tot]=head[u];
e[tot].len=w;
head[u]=tot;
}
inline void superadd(int u,int v,int w)
{
addedge(u,v,w);
addedge(v,u,w);
}
接下来跑spfa 用dfs思想
如果某个点出现多次 那么就出现了负环
inline void spfa(int u)
{
if(!flag) return;
vis[u]=true;
for(int i=head[u];i;i=nxxt[i])
{
if(!flag) return;
int y=e[i].to;
if(dis[y]>dis[u]+e[i].len)
{
dis[y]=dis[u]+e[i].len;
if(vis[y])
{
flag=false;
return;
}
else spfa(y);
}
}
vis[u]=false;
}
敲黑板
以下是重点
由于多组数据 我们需要claen
inline void clean()
{
tot=0;
flag=true;
memset(vis,false,sizeof vis);
memset(dis,0,sizeof dis);
memset(nxxt,0,sizeof nxxt);
memset(head,0,sizeof head);
}
正解代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 100010
#define M 1000010
struct edge
{
int to,len;
}e[M];
int head[N],dis[N],nxxt[M];
bool vis[N],flag;
int tot;
inline void addedge(int u,int v,int w)
{
tot++;
e[tot].to=v;
nxxt[tot]=head[u];
e[tot].len=w;
head[u]=tot;
}
inline void superadd(int u,int v,int w)
{
addedge(u,v,w);
addedge(v,u,w);
}
inline void clean()
{
tot=0;
flag=true;
memset(vis,false,sizeof vis);
memset(dis,0,sizeof dis);
memset(nxxt,0,sizeof nxxt);
memset(head,0,sizeof head);
}
inline void spfa(int u)
{
if(!flag) return;
vis[u]=true;
for(int i=head[u];i;i=nxxt[i])
{
if(!flag) return;
int y=e[i].to;
if(dis[y]>dis[u]+e[i].len)
{
dis[y]=dis[u]+e[i].len;
if(vis[y])
{
flag=false;
return;
}
else spfa(y);
}
}
vis[u]=false;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
clean();
int n,m,w;
scanf("%d%d%d",&n,&m,&w);
for(int i=1;i<=m;i++)
{
int begi,endd,leng;
scanf("%d%d%d",&begi,&endd,&leng);
superadd(begi,endd,leng);
}
for(int i=1;i<=w;i++)
{
int begi,endd,leng;
scanf("%d%d%d",&begi,&endd,&leng);
addedge(begi,endd,-leng);
}
for(int i=1;i<=n;i++)
{
if(!flag) break;
spfa(i);
}
if(flag) puts("NO");
else puts("YES");
}
}
写在最后
bfs找负环确实没有dfs快

这篇博客讨论了如何解决USACO2006 December Gold题目Wormholes(虫洞),涉及到寻找农场中利用虫洞回到过去的路径。通过输入农场数量、地的数量、小路和虫洞的数量,以及描述这些元素的详细信息,判断是否可能回到过去。作者分享了使用DFS(深度优先搜索)而非SPFA(Shortest Path Faster Algorithm)的方法,因为DFS在空间效率上有所提升,并给出了代码实现。

被折叠的 条评论
为什么被折叠?



