题解 P1807 【最长路_NOI导刊2010提高(07)】
思路:SPFA加判负环,因为边权加边的时候变负,最后答案再取负。
不多说,上代码:
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N = 500005;
const int INF = 2147483647;
struct Edge {
int next, to, w;
}e[N];
int n,m,x,y,w,head[N],vis[N],dis[N],cnt[N],tot;
queue < int > q;
void spfa()
{
vis[1] = 1;//标记入队
dis[1] = 0;
cnt[1] = 1;//cnt是记录第几步
q.push(1);
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = 0;//出队
for (int i=head[u]; i!=-1; i=e[i].next) {
int v = e[i].to;
if (dis[u] + e[i].w < dis[v])
{
cnt[v] = cnt[u] +1;//步数加1
if (cnt[v] > n) return;//如果一条边的步数超过了点的个数便已经是负环了,没必要再继续找
dis[v] = dis[u] + e[i].w;//更新
if (vis[v] == 0)//入队
{
q.push(v);
vis[v] = 1;
}
}
}
}
}
void add(int from, int to, int W) {//邻接表加边
tot ++;
e[tot].to = to;
e[tot].w = W;
e[tot].next = head[from];
head[from] = tot;
}
int main()
{
memset(head, -1, sizeof(head));//初始化
scanf("%d %d", &n, &m);
for (int i=1; i<=n; i++) {//初始化
vis[i] = 0;
dis[i] = INF;
}
for (int i=1; i<=m; i++) {
scanf("%d %d %d", &x, &y, &w);
add(x, y, -w);//权值取负
}
spfa();
if (dis[n] == INF) printf("-1"); else//值不变即不连通
printf("%d", -dis[n]);//否则输出取负的答案
return 0;
}