最短路问题,而且涉及到判断环路的问题。
判断负环的两种方法:
SPFA思想:如果存在一个点进入队列的次数超过N次,则存在负环。
bellman_ford思想:对所有的边进行v-1 松弛即如果 dis[u]+map[u][v] < dis[v] 则 dis[v] = dis[u]+map[u][v],若v-1次松弛之后还能进行松弛,说明原图存在负环。复杂度 0(VE) 。
我用的是SPFA判断环,代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define CLR(a,b) memset(a,b,sizeof(a))
#define MAX 0xfffffff
#include<queue>
using namespace std;
const int INF1=1010;
const int INF2=2010;
int First[INF2],Next[INF2],Key[INF2],Num[INF2],relaxnum[INF1],visit[INF1],dis[INF1];
int n,m,top;
void initial()
{
CLR(First,-1);
CLR(Next,-1);
CLR(relaxnum,0);
top=0;
}
void add(int to,int back,int cost) //邻接表存图
{
Key[top]=cost;
Next[top]=First[to];
Num[top]=back;
First[to]=top++;
}
int Dijkstra_SPFA(int start)
{
CLR(visit,0);
queue<int>q;
while(!q.empty())
q.pop();
for(int i=0;i<INF1;i++) dis[i]=-MAX;
dis[start]=0;
q.push(start);
visit[start]=1;
while(!q.empty())
{
int cur=q.front();
q.pop();
visit[cur]=0;
for(int i=First[cur];i!=-1;i=Next[i])
{
if(dis[cur]+Key[i]>dis[Num[i]])
{
dis[Num[i]]=dis[cur]+Key[i];
if(!visit[Num[i]])
{
q.push(Num[i]);
if(++relaxnum[Num[i]]>n) //判断是否存在正无穷环。
return 1;
visit[Num[i]]=1;
}
}
}
}
return 0;
}
int main()
{
int ncase;
cin>>ncase;
while(ncase--)
{
initial();
scanf("%d%d",&n,&m);
int a,b,c,d,e;
bool flag=false;
for(int i=0;i<m;i++)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
if((d-c>0 && e-c>0) || (d-c>=0 && e-c>0) || (d-c>0 && e-c>=0)) //该种情况肯定能赚无穷多资金
{
flag=true;
continue;
}
add(a,b,d-c);
add(b,a,e-c);
}
if(flag || Dijkstra_SPFA(0))
printf("$$$\n");
else printf("%d\n",dis[n-1]);
}
return 0;
}