题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=183
解题思路:
最短路裸题。
最长路+判断正环
学会的东西是如何用SPFA判断负环,可以用一个数组维护每个节点入队的次数,超过n次就肯定有负环出现。
代码如下:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<climits>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int MAX = INT_MAX >> 1;
const int N = 1010;
const int M = 2010;
#define CLR(arr, what) memset(arr, what, sizeof(arr))
int Key[M], Next[M], Num[M], Head[N], top;
int dis[N], visit[N], relaxnum[N];
int n, m;
void init()
{
CLR(Head, -1);
CLR(Next, -1);
CLR(relaxnum, 0);
top = 0;
}
void add(int u, int v, int cost)
{
Key[top] = cost;
Next[top] = Head[u];
Num[top] = v;
Head[u] = top++;
}
int SPFA(int start)
{
queue<int> q;
while(!q.empty())
q.pop();
CLR(visit, false);
for(int i = 0; i < N; ++i)
dis[i] = -MAX;
dis[start] = 0;
visit[start] = true;
q.push(start);
while(!q.empty())
{
int cur = q.front();
q.pop();
visit[cur] = false;
for(int i = Head[cur]; i != -1; i = Next[i])
{
if(dis[Num[i]] < dis[cur] + Key[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]] = true;
}
}
}
}
return 0;
}
int main()
{
int ncase;
bool flag;
int start, end, spend, to, back;
scanf("%d", &ncase);
while(ncase--)
{
init();
flag = false;
scanf("%d%d", &n, &m);
for(int i = 0; i < m; ++i)
{
scanf("%d%d%d%d%d", &start, &end, &spend, &to, &back);
if((to - spend > 0 && back - spend >= 0) || (to - spend >= 0 && back - spend > 0) || (to - spend > 0 && back - spend > 0))
{
flag = true;
continue;
}
add(start, end, to - spend);
add(end, start, back - spend);
}
if(flag == true || SPFA(0))
printf("$$$\n");
else
printf("%d\n", dis[n - 1]);
}
return 0;
}