POJ3259 Wormholes 洛谷P3385 【模板】负环
2017-08-04 13:20
267 查看
题目来源:http://poj.org/problem?id=3259 https://www.luogu.org/problem/show?pid=3385
这两个题本质均是判断给定图中是否存在负环。
先来看POJ上的题。使用SPFA算法,记录运行过程中某点进队列的次数,如果超过n次则一定存在负环。
代码1:
再来看洛谷上的这个题,题目几乎是一样的,但洛谷的数据范围更大一些,用上述算法会TLE。
那就需要进行一些优化。
首先题目只是判断是否存在负环,而SPFA的主要功能是求最短路,更新每个节点的最短路是没必要的。
在SPFA算法运行之前,要把除原点外的所有点的dis值赋成inf,这样dis函数会不断进行更新。
而本题只需要判断是否存在负环,故开始时将dis值全部赋为0并不影响判断结果(因为如果存在负环,那么也会存在环上靠近负权值的边的点入队列n次的情况),这样可大大减少运算量,因为大多数点到原点的dis值是>0的。
这样找的负环的是从某一条负权值的边开始的,需要枚举每个点作为起点。
代码2:
这两个题本质均是判断给定图中是否存在负环。
先来看POJ上的题。使用SPFA算法,记录运行过程中某点进队列的次数,如果超过n次则一定存在负环。
代码1:
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #include <queue> using namespace std; int n,m,q; const int maxn=200005; struct data{int to,next,w;}e[maxn*2]; int head[maxn]; bool inq[maxn]; int cnt=0; int dis[maxn]; queue<int> que; int tot[maxn]; void ins(int u,int v,int val) { e[++cnt].to=v; e[cnt].w=val; e[cnt].next=head[u]; head[u]=cnt; } bool spfa(int s) { dis[s]=0;inq[s]=1;++tot[s]; while(!que.empty())que.pop(); que.push(s); while(!que.empty()) { int x=que.front(); que.pop(); inq[x]=0; for(int i=head[x];i;i=e[i].next) { int u=e[i].to; if(dis[u]>dis[x]+e[i].w) { dis[u]=dis[x]+e[i].w; if(!inq[u]) { inq[u]=1; que.push(u); ++tot[u]; if(tot[u]>n)return 0; } } } } return 1; } int main() { ios::sync_with_stdio(0);cin.tie(0); int _;cin>>_; while(_--) { memset(head,0,sizeof(head)); memset(dis,63,sizeof(dis)); memset(e,0,sizeof(e)); memset(tot,0,sizeof(tot)); memset(inq,0,sizeof(inq)); cnt=0; cin>>n>>m>>q; for(int i=1;i<=m;i++) { int s,t,val; cin>>s>>t>>val; ins(s,t,val); ins(t,s,val); } for(int i=1;i<=q;i++) { int s,t,val; cin>>s>>t>>val; ins(s,t,(-1)*val); } bool ok=0; for(int i=1;i<=n;i++) { if(dis[i]>1000000000) { if(!spfa(i)){ok=1;break;} } } if(ok)puts("YES"); else puts("NO"); } return 0; }
再来看洛谷上的这个题,题目几乎是一样的,但洛谷的数据范围更大一些,用上述算法会TLE。
那就需要进行一些优化。
首先题目只是判断是否存在负环,而SPFA的主要功能是求最短路,更新每个节点的最短路是没必要的。
在SPFA算法运行之前,要把除原点外的所有点的dis值赋成inf,这样dis函数会不断进行更新。
而本题只需要判断是否存在负环,故开始时将dis值全部赋为0并不影响判断结果(因为如果存在负环,那么也会存在环上靠近负权值的边的点入队列n次的情况),这样可大大减少运算量,因为大多数点到原点的dis值是>0的。
这样找的负环的是从某一条负权值的边开始的,需要枚举每个点作为起点。
代码2:
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,m,q; const int maxn=200005; struct data{int to,next,w;}e[maxn*2]; int head[maxn]; int cnt=0; int dis[maxn]; bool vis[maxn]; void ins(int u,int v,int val) { e[++cnt].to=v; e[cnt].w=val; e[cnt].next=head[u]; head[u]=cnt; } bool dfs(int s) { vis[s]=1; for(int i=head[s];i;i=e[i].next) { int x=e[i].to; if(dis[x]>dis[s]+e[i].w) { if(vis[x])return 0; dis[x]=dis[s]+e[i].w; if(!dfs(x))return 0; } } vis[s]=0; return 1; } int main() { int _;scanf("%d",&_); while(_--) { memset(head,0,sizeof(head)); memset(dis,0,sizeof(dis)); memset(vis,0,sizeof(vis)); memset(e,0,sizeof(e)); cnt=0; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int s,t,val; scanf("%d%d%d",&s,&t,&val); if(val<0)ins(s,t,val); else { ins(s,t,val); ins(t,s,val); } } bool ok=0; for(int i=1;i<=n;i++) { if(!dfs(i)){ok=1;break;} } if(ok)puts("YE5"); else puts("N0"); } return 0; }
相关文章推荐
- POJ3259 Wormholes(最短路,有无负环,spfa,模板)
- Wormholes---poj3259(最短路 spfa 判断负环 模板)
- POJ3259 Wormholes(spfa判断负环模板题)
- POJ3259 Wormholes 【SPFA判断负环】
- 【洛谷1593】【模板】template负环 递归SPFA判负环
- POJ-3259 Wormholes(判断负环、模板)
- POJ3259 Wormholes 找负环
- 洛谷 P3385 判负环dfs
- poj3259 Wormholes(floyd||spfa判断负环)
- [模板]poj3259(判断是否存在负环)
- POJ3259---Wormholes(最短路:验证存在负环)
- POJ3259----Wormholes(SPFA判断负环)
- POJ3259-Wormholes(SPFA 判负环)
- [poj3259]Wormholes(spfa判负环)
- 洛谷—— P3385 【模板】负环
- POJ3259 - Wormholes(连通图判断负环)
- Poj3259 Wormholes (找负环)
- POJ3259 - Wormholes - 最短路判负环
- poj3259: Wormholes(BF模板题)
- POJ3259 Wormholes(Bellmanford判断负环)