POJ3259 - Wormholes - 判负l环 - SPA模板题
题意
(两点间有两种路径可选择,一条是花费时间,一条是增加时间,问是否存在环,使得在走过这个环后耗费时间小于等于0。)
问某个人是否可以从他所在的起点开始出发,最后回到该点,也就是说,如果可以回到该点,说明形成了一个环,说明存在负环,所以最后判断负环即可。
给出T组数据,每组数据给出n、m、w,分别代表n个田地、m条路径、w个虫洞。接下去再给出m条双向路径(正常的路径)和w条单向路径(虫洞的路径)。
思路
判断负环的SPFA模板题。
SPFA写法
#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<cmath>
#include<list>
#include<stdlib.h>
#include<map>
#include<stack>
#include<stdio.h>
#include<queue>
using namespace std;
typedef long long ll;
#define sc(T) scanf("%d",&T)
#define scc(x,y) scanf("%d %d",&x,&y)
#define pr(T) printf("%d\n",T)
#define f(a,b,c) for (int a=b;a<c;a++)
#define ff(a,b,c) for (int a=b;a>c;a--)
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
#define eps 1e-9
#define PI acos(-1)
const int N=520;
const int M=2500;
int n,tot,dis[N],head[N],cnt[N];
bool book[N];
//cnt记录每个点入队的次数,间接用来判断负环(cnt根据题意开)
struct node
{
int v,w,nex;
} e[M<<2];
void add(int u,int v,int w)
{
e[++tot].v=v;
e[tot].w=w;
e[tot].nex=head[u];
head[u]=tot;
}
bool SPFA()
{
for(int i=1; i<=n; i++)
book[i]=0,cnt[i]=0,dis[i]=inf;
queue<int>Q;
// 注意:队列开在外面会造成内存超限,
//因为开在函数内部函数结束后就会释放内存,开在外面就相当于全局变量就不会释放内存
//如果只执行一次就没区别
//但是可以自己先手动清空队列再用
Q.push(1);
dis[1]=0,book[1]=1,cnt[1]++;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
book[u]=0;
for(int i=head[u]; i!=-1; i=e[i].nex)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(!book[v])
Q.push(v),cnt[v]++,book[v]=1;
if(cnt[v]==n) // 如果不存在负环最多更新n-1次
return 0;
}
}
}
return 1;
}
int main()
{
int T,m,w,x,y,z;
sc(T);
while(T--)
{
tot=-1,mem(head,-1);
cin>>n>>m>>w;//n个田地、m条路径、w个虫洞
f(i,0,m) // 正常的路是双向的
{
cin>>x>>y>>z;
add(x,y,z),add(y,x,z);
}
f(i,0,w) // 虫洞代表负权路
{
cin>>x>>y>>z;
add(x,y,-z);
}
if(SPFA())
cout<<"NO"<<endl;
else
cout<<"YES"<<endl;
}
return 0;
}
Dijkstra写法
#include<iostream>
#include<iomanip>
#include<string.h>
#include<set>
#include<stdio.h>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
int u[7550],v[7550],w[7550],dis[7550];
int bak[2550];
int main()
{
// std::ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int f,n,m,ww;
cin>>f;
while(f--)
{
cin>>n>>m>>ww;
int aa,bb,cc;
int p=1;
for(int i=1; i<=m+ww; i++)
{
cin>>aa>>bb>>cc;
if(i<=m)
{
u[p]=aa;
v[p]=bb;
w[p]=cc;
p++;
u[p]=bb;
v[p]=aa;
w[p]=cc;
p++;
}
else
{
u[p]=aa;
v[p]=bb;
w[p]=-cc;
p++;
}
}
for(int i=1; i<=n; i++)
dis[i]=inf;
dis[1]=0;
int check;
for(int k=1; k<=n-1; k++)
{
check=0;
for(int i=1; i<=m*2+ww; i++)
{
if(dis[v[i]]>dis[u[i]]+w[i])
{
dis[v[i]]=dis[u[i]]+w[i];
check=1;
}
}
if(check==0)
break;
}
int flag=0;
for(int i=1; i<=m*2+ww; i++)
{
if(dis[v[i]]>dis[u[i]]+w[i])
flag=1;
}
if(flag)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}