图论
最短路径
例题:
743. 网络延迟时间
朴素Dijkstra
算法:
st:当前已确定最短距离的点的集合
dist[1] = 0, dist[i] = INF
for i 1 ~ n:
t : 不在st中,距离最近的点
将t加入st
用t更新其他点的距离
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
List<int[]>[] g = new List[n + 1];
Arrays.setAll(g, (a) -> new ArrayList<>());
for(int[] t : times){
int a = t[0], b = t[1], c = t[2];
g[a].add(new int[]{b, c});
}
int[] dist = new int[n + 1];
boolean[] st = new boolean[n + 1];
Arrays.fill(dist, 0x3f3f3f);
dist[k] = 0;
for(int i = 0; i < n; i++){
int t = -1;
for(int j = 1; j <= n; j++){
if(!st[j] && (t == -1 || dist[t] > dist[j])){
t = j;
}
}
st[t] = true;
for(int[] nei : g[t]){
int a = nei[0], b = nei[1];
dist[a] = Math.min(dist[a], dist[t] + b);
}
}
int res = 0;
for(int i = 1; i <= n; i++){
if(dist[i] == 0x3f3f3f) return -1;
res = Math.max(res, dist[i]);
}
return res;
}
}
Bellman-ford
算法:
for n次
for 所有边 a , b, w
dist[b] = Math.min(dist[b], dist[a] + w)
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
int[] dist = new int[n + 1], backup = new int[n + 1];
Arrays.fill(dist, 0x3f3f3f);
dist[k] = 0;
for(int i = 0; i < n; i++){
backup = dist.clone();
for(int[] t : times){
int a = t[0], b = t[1], c = t[2];
dist[b] = Math.min(dist[b], backup[a] + c);
}
}
int ans = 0;
for(int i = 1; i <= n; i++){
if(dist[i] == 0x3f3f3f) return -1;
ans = Math.max(ans, dist[i]);
}
return ans;
}
}
SPFA
算法:
queue <--- 1
while queue不空
t <--- queue.poll();
更新t的所有出边 t---w---b
queue <--- b
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
List<int[]>[] g = new List[n + 1];
Arrays.setAll(g, (a) -> new ArrayList<>());
for(int[] t : times){
int a = t[0], b = t[1], c = t[2];
g[a].add(new int[]{b, c});
}
int[] dist = new int[n + 1];
boolean[] st = new boolean[n + 1];//st[i] : i是否在队列中
Arrays.fill(dist, 0x3f3f3f);
dist[k] = 0;
st[k] = true;
Deque<Integer> q = new ArrayDeque<>();
q.offer(k);
while(!q.isEmpty()){
int cur = q.poll();
st[cur] = false;
for(int[] nei : g[cur]){
int a = nei[0], b = nei[1];
if(dist[a] > dist[cur] + b){
dist[a] = dist[cur] + b;
if(!st[a]) {
q.offer(a);
st[a] = true;
}
}
}
}
int res = 0;
for(int i = 1; i <= n; i++){
if(dist[i] == 0x3f3f3f) return -1;
res = Math.max(res, dist[i]);
}
return res;
}
}
spfa判断负环
拉近距离
题目背景
我是源点,你是终点。我们之间有负权环。 ——小明
题目描述
在小明和小红的生活中,有 N N N 个关键的节点。有 M M M 个事件,记为一个三元组 ( S i , T i , W i ) (S_i,T_i,W_i) (Si,Ti,Wi),表示从节点 S i S_i Si 有一个事件可以转移到 T i T_i Ti,事件的效果就是使他们之间的距离减少 W i W_i Wi。
这些节点构成了一个网络,其中节点 1 1 1 和 N N N 是特殊的,节点 1 1 1 代表小明,节点 N N N 代表小红,其他代表进展的阶段。所有事件可以自由选择是否进行,但每次只能进行当前节点邻接的。请你帮他们写一个程序,计算出他们之间可能的最短距离。
输入格式
第一行,两个正整数 N , M N,M N,M。
之后 M M M 行,每行 3 3 3 个空格隔开的整数 S i , T i , W i S_i,T_i,W_i Si,Ti,Wi。
输出格式
一行,一个整数表示他们之间可能的最短距离。如果这个距离可以无限缩小,输出Forever love
。
样例 #1
样例输入 #1
3 3
1 2 3
2 3 -1
3 1 -10
样例输出 #1
-2
提示
对于 20 % 20\% 20% 数据, N ≤ 10 N \le 10 N≤10, M ≤ 50 M \le 50 M≤50。
对于 50 % 50\% 50% 数据, N ≤ 300 N \le 300 N≤300, M ≤ 5000 M \le 5000 M≤5000。
对于 100 % 100\% 100% 数据, 1 ≤ N ≤ 1 0 3 1\le N \le 10^3 1≤N≤103, 1 ≤ M ≤ 1 0 4 1\le M \le 10^4 1≤M≤104, ∣ W i ∣ ≤ 100 |W_i|\le 100 ∣Wi∣≤100,保证从节点 1 1 1 到 2 … N 2 \dots N 2…N 有路径,从节点 N N N 到 1 … N − 1 1 \dots N - 1 1…N−1 有路径。
import java.util.*;
public class P2136 {
static final int N = 1010, M = 10010, INF = 0x3f3f3f;
static int n, m;
static int[] dist = new int[N], cnt = new int[N];
static boolean[] st = new boolean[N];
static List<int[]>[] g = new List[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
Arrays.setAll(g, (a) -> new ArrayList<>());
int s, t, w;
for(int i = 0; i < m; i++){
s = sc.nextInt();
t = sc.nextInt();
w = sc.nextInt();
g[s].add(new int[]{t, -w});
}
boolean f1 = spfa(1);
int ans1 = dist[n];
boolean f2 = spfa(n);
int ans2 = dist[1];
if(f1 || f2){
System.out.println("Forever love");
}else{
System.out.println(Math.min(ans1, ans2));
}
}
private static boolean spfa(int x) {
Arrays.fill(dist, INF);
Arrays.fill(cnt, 0);
dist[x] = 0;
Deque<Integer> q = new ArrayDeque<>();
q.offer(x);
st[x] = true;
while(!q.isEmpty()){
int cur = q.poll();
st[cur] = false;
for(int[] nei : g[cur]){
int t = nei[0], w = nei[1];
if(dist[t] > dist[cur] + w){
dist[t] = dist[cur] + w;
cnt[t] = cnt[cur] + 1;
if(cnt[t] >= n) {
return true;
}
if(!st[t]){
q.offer(t);
st[t] = true;
}
}
}
}
return false;
}
}