题解【洛谷P1938】 [USACO09NOV]找工就业Job Hunt

题面

题解

将路径连边\((x, y, d)\) ,将航线连边\((x, y, d - w)\)。其中线路是从\(x\)\(y\),航线的费用为\(w\)\(d\)的含义如题面。

跑一遍\(SPFA\)最长路即可。

注意判断负环的情况,此时要输出\(-1\)

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <queue>
#define gI gi
#define itn int
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)

using namespace std;

inline int gi()
{
    int f = 1, x = 0; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
    return f * x;
}

int d, p, c, f, s, tot, head[1003], nxt[1003], ver[1003], edge[1003], in[1003], ans, dis[1003];
int vis[1003];
queue <int> q;

inline void add(int u, int v, int w)
{
	ver[++tot] = v, edge[tot] = w, nxt[tot] = head[u], head[u] = tot;
}

inline void SPFA()
{
	q.push(s);
	vis[s] = 0;
	dis[s] = d;
	in[s] = 1;
	while (!q.empty())
	{
		int u = q.front(); q.pop();
		vis[u] = 0;
		++in[u];//统计入队次数
		if (in[u] > c) {puts("-1"); exit(0);}//负环
		for (int i = head[u]; i; i = nxt[i])
		{
			int v = ver[i], w = edge[i];
			if (dis[v] < dis[u] + w)//注意是小于号
			{
				dis[v] = dis[u] + w;
				if (!vis[v])
				{
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
}

int main()
{
	//File("P1938");
	d = gi(), p = gI(), c = gI(), f = gI(), s = gI();
	for (int i = 1; i <= p; i+=1)
	{
		int u = gI(), v = gI();
		add(u, v, d);//连边
	}
	for (int i = 1; i <= f; i+=1)
	{
		int u = gi(), v = gI(), w = gi();
		add(u, v, d - w);//连边
	}
	SPFA();//SPFA最长路
	int maxx = 0;
	for (int i = 1; i <= c; i+=1) maxx = max(maxx, dis[i]);
	printf("%d\n", maxx);
	return 0;
}
posted @ 2019-08-07 16:45  csxsi  阅读(138)  评论(0编辑  收藏  举报