【蓝桥杯集训15】求最短路存在负权边——spaf算法(2 / 4)
创始人
2024-05-29 04:24:26

——SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称

单源最短路,且图中没有负环就可以用spfa

目录

spaf求最短路模板

852. spfa判断负环 

341. 最优贸易 - 

3305. 作物杂交 - 


spaf求最短路模板

只有当一个点的前驱结点更新了,该节点才会得到更新

因此只需要创建一个队列每一次加入距离被更新的结点

队列存的是待更新的节点——取出队列里的节点会更新它的后续节点

已经在队列的节点不需要重复入队,可以用st数组标记已入队节点

spfa算法步骤:

  • 建立队列,队列初始只有节点1
  • 取出队头节点x,取消该点标记,遍历x所有出边(x,y,z),若dist[y]>dist[x]+w,则更新最短路dist[y]=dist[x]+w,若y不在队列中,让y入队并标记
  • 重复上述步骤,直到队列为空
  • 注:dist[x]存1→x的最短路径长度  st[x]标记x节点是否在队列中

活动 - AcWing

题目:

给定n个点m条边的带权有向图,图中可能存在重边和自环,边权可能为负数

请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 impossible。

数据保证不存在负权回路。

/**道阻且长,行则将至*author:Roye_ack
*/
import java.util.*;
import java.io.*;
import java.math.*;class Main
{static PrintWriter wt=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));static int N=100010;static int n,m,idx;static int[] h=new int[N],e=new int[N],ne=new int[N],w=new int[N];static int[] dist=new int[N];static int[] st=new int[N];public static void add(int a,int b,int c){e[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx++;}public static int spaf(){Queue q=new LinkedList<>();q.offer(1);Arrays.fill(dist,0x3f3f3f3f);dist[1]=0;st[1]=1;while(!q.isEmpty()){var t=q.poll();st[t]=0;for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(dist[j]>dist[t]+w[i]){dist[j]=dist[t]+w[i];if(st[j]==0) //如果当前队列里不存在该节点 则入队并标记{q.offer(j);st[j]=1;}}}}return dist[n];}public static void main(String[] args) throws IOException{n=rd.nextInt();m=rd.nextInt();Arrays.fill(h,-1);while(m-->0){int a=rd.nextInt(),b=rd.nextInt(),c=rd.nextInt();add(a,b,c);}int res=spaf();if(res==0x3f3f3f3f) wt.print("impossible");else wt.print(res);wt.flush();}static class rd{static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));static StringTokenizer tk=new StringTokenizer("");static String nextLine() throws IOException{return bf.readLine();}static String next() throws IOException{while(!tk.hasMoreTokens()) tk=new StringTokenizer(bf.readLine());return tk.nextToken();}static int nextInt() throws IOException{return Integer.parseInt(next());}static double nextDouble() throws IOException{return Double.parseDouble(next());}static long nextLong() throws IOException{return Long.parseLong(next());}static BigInteger nextBig() throws IOException{BigInteger d=new BigInteger(rd.nextLine());return d;}}
}class PII
{int x,y;PII(int x,int y){this.x=x;this.y=y;}
}

 

852. spfa判断负环 

活动 - AcWing

题目:

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数

请你判断图中是否存在负权回路

思路:

在spfa基础上添加一个cnt数组,cnt[x]存1→x经过的边数

边数cnt的更新方式:cnt[x]=cnt[t]+1(1到t的边数+1)

判断负环原理:

  • 如果cnt[x]≥n,说明1~x至少经过了n+1个点,由抽屉原理可知至少两个点的编号一样
  • 由于只有当dist[x]
  • 综上可判断图中存在负环
/**道阻且长,行则将至*author:Roye_ack
*/
import java.util.*;
import java.io.*;
import java.math.*;class Main
{static PrintWriter wt=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));static int N=100010;static int n,m,idx;static int[] h=new int[N],e=new int[N],ne=new int[N],w=new int[N];static int[] dist=new int[N],cnt=new int[N]; //cnt用于存边数static int[] st=new int[N];public static void add(int a,int b,int c){e[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx++;}public static boolean spaf(){Queue q=new LinkedList<>();//这里不用初始化dist数组为 正无穷/初始化的原因是:如果存在负环,那么dist不管初始化为多少,都会被更新for(int i=1;i<=n;i++) //该题是判断是否存在负环,并非判断是否存在从1开始的负环,因此需要将所有的点都加入队列中,更新周围的点{q.offer(i);st[i]=1;}while(!q.isEmpty()){var t=q.poll();st[t]=0;for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(dist[j]>dist[t]+w[i]){dist[j]=dist[t]+w[i];cnt[j]=cnt[t]+1;if(cnt[j]>=n) return true;if(st[j]==0){q.offer(j);st[j]=1;}}}}return false;}public static void main(String[] args) throws IOException{n=rd.nextInt();m=rd.nextInt();Arrays.fill(h,-1);while(m-->0){int a=rd.nextInt(),b=rd.nextInt(),c=rd.nextInt();add(a,b,c);}if(spaf()) wt.print("Yes");else wt.print("No");wt.flush();}static class rd{static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));static StringTokenizer tk=new StringTokenizer("");static String nextLine() throws IOException{return bf.readLine();}static String next() throws IOException{while(!tk.hasMoreTokens()) tk=new StringTokenizer(bf.readLine());return tk.nextToken();}static int nextInt() throws IOException{return Integer.parseInt(next());}static double nextDouble() throws IOException{return Double.parseDouble(next());}static long nextLong() throws IOException{return Long.parseLong(next());}static BigInteger nextBig() throws IOException{BigInteger d=new BigInteger(rd.nextLine());return d;}}
}class PII
{int x,y;PII(int x,int y){this.x=x;this.y=y;}
}

 

341. 最优贸易 - 

活动 - AcWing

题目:

思路:

 

3305. 作物杂交 - 

3305. 作物杂交 - AcWing题库 

题目:

思路:

 

相关内容

热门资讯

世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...