惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
D
Docker
S
SegmentFault 最新的问题
博客园 - 聂微东
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
GbyAI
GbyAI
L
LangChain Blog
Vercel News
Vercel News
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
T
Threat Research - Cisco Blogs
T
Threatpost
Scott Helme
Scott Helme
T
Tailwind CSS Blog
Latest news
Latest news
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
The Register - Security
The Register - Security
罗磊的独立博客
P
Proofpoint News Feed
腾讯CDC
S
Schneier on Security
雷峰网
雷峰网
A
About on SuperTechFans
T
Tenable Blog
F
Full Disclosure
Cyberwarzone
Cyberwarzone
博客园_首页
有赞技术团队
有赞技术团队
K
Kaspersky official blog

文章列表

Claude Opus 4.8来了!不再是比聪明,而是更能干活,敢于认错,变得诚实了! Note.ms在线简洁匿名记事本,如何修改/0页面 解禁了?RTX 5090 PRO6000上架京东自营店 用工具轻松的给Frpc配置SSL证书,穿透Http与Https流量,开启强制Https跳转 「POJ1740」A New Stone Game SG函数与博弈论题解 Deepseek V4发布了!综合能力比肩顶级闭源模型! 国内就可以使用的免费SuperGrok,无需登录无需排队,完全公益免费! 保姆级干货:在AI时代薅羊毛,如何获得大量免费的AI API?学完这个你的小龙虾就不缺粮食了! Deepseek-V4要来了的预兆?Deepseek专家模式低调上新!Deepseek首次引入模式分层! 游玩本站必读公告 Claude Code源代码惨遭泄露,几句话告诉你泄露的原因,附下载链接 Docker快速部署Astrbot,开源的一站式 Agentic 个人和群聊助手 今天是愚人节,请将这篇文章转发给你的亲朋好友 P4171 [JSOI2010] 满汉全席 2-SAT详细题解 P1993 小 K 的农场 差分约束SPFA判断负环 详细题解 P6145 [USACO20FEB] Timeline G SPFA差分约束最长路题解 Luogu P2850 [USACO06DEC] Wormholes G SPFA算法思路与C++代码详解 开源 UI 元素社区库,让你的网站更加美观! 免费的AI和付费的API区别到底在哪里?付费的AI真的更聪明吗?
Luogu P2136 拉近距离 SPFA判断负环题解 与 思路
PYM · 2026-03-21 · via

题目

Luogu P2136

题目背景

我是源点,你是终点。我们之间有负权环。 ——小明

题目描述

在小明和小红的生活中,有 N 个关键的节点。有 M 个事件,记为一个三元组 (Si,Ti,Wi),表示从节点 Si 有一个事件可以转移到 Ti,事件的效果就是使他们之间的距离减少 Wi

这些节点构成了一个网络,其中节点 1N 是特殊的,节点 1 代表小明,节点 N 代表小红,其他代表进展的阶段。所有事件可以自由选择是否进行,但每次只能进行当前节点邻接的。请你帮他们写一个程序,计算出他们之间可能的最短距离。

输入格式

第一行,两个正整数 N,M

之后 M 行,每行 3 个空格隔开的整数 Si,Ti,Wi

输出格式

一行,一个整数表示他们之间可能的最短距离。如果这个距离可以无限缩小,输出Forever love

输入输出样例

输入 #1

3 3
1 2 3
2 3 -1
3 1 -10

输出 #1

-2

说明/提示

对于 20% 数据,N≤10M≤50

对于 50% 数据,N≤300M≤5000

对于 100% 数据,1≤N≤1031≤M≤104Wi∣≤100,保证从节点 12…N 有路径,从节点 N1…N−1 有路径。

思路

这道题很显然是一道单源最短路的题目,通过观察题目,我们可以得出以下信息:

  • 是单向图

  • 计算的是小红与小明之间的最短距离,这意味着可以是小红到小明,也可以是小明到小红

  • 题目有明显的负环,需要输出 Forever love

  • 题目中的边权不是相加是相减,为了避免麻烦改代码,可以对边权取反来建图。

那么这道题是非常良心的👍,出题人没有卡SPFA,所以我们使用SPFA来求解。

对于SPFA来找负环,可以建立一个 cntcnt 数组,我们定义 𝑐𝑛𝑡[𝑖] 表示点 𝑖 距离源点经过的边数 每次 𝑖 → 𝑗 转移的时候 𝑐𝑛𝑡[𝑗] = 𝑐𝑛𝑡[𝑖] + 1 如果有点的 𝑐𝑛𝑡 大于等于 𝑛 时说明有负环,就直接输出 Forever love

多说无益,我们看代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
// N是数组大小,INF用来给dis赋初始值,即极大值
const int N = 1000 + 5, INF = 100000000;
int n, m;
vector<vector<pair<int, int>>> e(N); // 比较奇葩的STL写法,不喜欢的可以写结构体
ll dis[N]; // 记录从起点到任意点的最短距离的数组
bool vis[N]; // 判断任意点是否在队列中
int cnt[N]; // 记录任意点的出队次数,用来判断负环
void spfa(int s) {
	// SPFA的初始化
	fill(dis + 1, dis + n + 1, INF); 
	fill(vis + 1, vis + n + 1, false);
	fill(cnt + 1, cnt + n + 1, 0);
	dis[s] = 0, vis[s] = true;
	queue<int> q;
	q.emplace(s);
	
	// SPFA
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		vis[u] = false; // 标记点u不在队列中了
		for (pair<int, int> tmp : e[u]) { //适配C++14的写法
			int v, w;
			tie(v, w) = tmp;
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				cnt[v] = cnt[u] + 1; // 找负环
				if (cnt[v] >= n) {
					cout << "Forever love\n"; // 有负环
					exit(0);
				}
				if (!vis[v]) {
					vis[v] = true; // 点v在队列中了
					q.emplace(v); // 把点v加入队列
				}
			}
		}
	}
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		int u, v, w;
		cin >> u >> v >> w;
		e[u].emplace_back(v, -w); // 对边权取反,方便处理
	}
	spfa(1); // 从小明到小红
	ll ans1 = dis[n];
	spfa(n); // 从小红到小明
	ll ans2 = dis[1];
	cout << min(ans1, ans2) << "\n"; // 对两个答案取较小值
	return 0;
}

代码提交结果如下: