SPFA求负环
注意事项:
1. 不要让一个点出队n次就算负环,如果只有一个点呢?出队n+1次费不了多少时间。
2. 从终点往回遍历不到的点即便有负环也无所谓,因为它根本无法在s → t的路径上累加负权值。
3. 此题注意删边方法。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define N 3000
#define M 101000
using namespace std;
//只能走权值最小的边
struct Syndra
{
int u,v,w,len,next;
}e[M];
int head[N],cnt;
int dist[N],len[N],visit[N],s,t,n,m;
int mini[N],able[N],num[N];
void add(int u,int v,int w,int len)
{
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].len=len;
e[cnt].next=head[u];
head[u]=cnt;
}
void spfa()
{
int i,j,k,u,v;
queue<int> q;
memset(dist,0x3f,sizeof(dist));
memset(visit,0,sizeof(visit));
memset(len,0x3f,sizeof(len));
memset(num,0,sizeof(num));
q.push(s);
dist[s]=len[s]=0;
visit[s]=1;
while(!q.empty())
{
u=q.front();
q.pop();
visit[u]=0;
if(!able[u])continue;
num[u]++;
if(num[u]>n)
{
printf("UNBOUND\n");
return;
}
for(i=head[u];i+1;i=e[i].next)
{
v=e[i].v;
if(!able[v])continue;
if(e[i].w>mini[u])continue;
if(dist[v]>dist[u]+e[i].w)
{
dist[v]=dist[u]+e[i].w;
len[v]=len[u]+e[i].len;
if(!visit[v])
{
visit[v]=1;
q.push(v);
}
}
else if(dist[v]==dist[u]+e[i].w)
{
if(len[v]>len[u]+e[i].len)
{
len[v]=len[u]+e[i].len;
if(!visit[v])
{
visit[v]=1;
q.push(v);
}
}
}
}
}
if(dist[t]==0x3f3f3f3f)
{
printf("VOID\n");
return ;
}
else
{
printf("%d %d\n",dist[t],len[t]);
return ;
}
}
char a,b,c;
void dfs(int x)
{
int i;
if(able[x])return ;
able[x]=1;
for(i=head[x];i+1;i=e[i].next)
{
if(e[i^1].w==mini[e[i].v])dfs(e[i].v);
}
}
void build()
{
int i,j,k;
cnt=-1;
memset(num,0,sizeof(num));
memset(able,0,sizeof(able));
memset(head,-1,sizeof(head));
memset(mini,0x3f,sizeof(mini));
for(i=1;i<=m;i++)
{
int u,v,w1,l,w2;
scanf(" %c%d%c%d%c%d%c%d%c%d%c",&a,&u,&a,&v,&a,&w1,&a,&l,&a,&w2,&a);
add(u,v,w1,l);
add(v,u,w2,l);
mini[u]=min(mini[u],w1);
mini[v]=min(mini[v],w2);
}
dfs(t);
}
int main()
{
// freopen("test.in","r",stdin);
while(scanf("%d%d%d%d",&n,&m,&s,&t)!=EOF)
{
build();
spfa();
}
return 0;
}