最短路问题(Dijkstra、Bellman-Ford、Floyd、SPFA)

Dijkstra

(加点法)

  • 适用于边权为正的情况
  • 适用于有向图和无向图
  • 可用于计算正权图上的单源最短路,即从单个源点出发,到所有结点的最短路。

伪代码

清除所有点的标号
设d[0] = 0,其他d[i] = INF
循环n次{
	在所有未标号的结点中,选出d值最小的结点x
	给结点x标记
	对于从x出发的所有边(x,y),更新d[y] = min{d[y], d[x]+w(x,y)}
} 
memset(v, 0, sizeof(v));
for(int i = 0; i < n; i++)
	d[i] = (i == 0 ? 0 : INF);
for(int i = 0; i < n; i++){
	int x,m = INF;
	for(int y = 0; y < n; y++)
		if(!v[y] && d[y] <= m)
			m = d[x = y];
	v[x] = 1;
	for(int y = 0; y < n; y++)
	d[y] = min(d[y], d[x] + w[x][y]);
}
const int INF = 100;
//寻找d最小的结点
int Min(int dist[], int vertexNum){
	int i,k;
	for(i = 0,k = 0;i<vertexNum; i++)
		if((dist[i]!=0)&&(dist[i]<dist[k]))
			k=i;
	return k;
}
void Dijkstra(int v){
	//num:已被标记的点的个数
	int num,dist[MaxSize];
	for(int i=0;i<vertexNum;i++){
		dist[i] = edge[v][i];
		if(dist[i]!=INF)
			path[i] = vertex[v]+vertex[i];
		else
			path[i] = "";
	}
	for(num = 1;num<vertexNum;num++){
		k = Min(dist,vertexNum);
		cout<<path[k]<<dist[k];
		//更新d
		if(dist[i]>dist[k]+edge[k][i]){
			dist[i] = dist[k]+edge[k][i];
			path[i] = path[k]+vertex[i];
		}
		dist[k]=0;
	}
}

Bellman-Ford

  • 路径包含负权
for(int i = 0; i < n; i++)
	d[i] = INF;
d[0] = 0;
//最短路径最多只经过(起点不算)n-1个结点
for(int k = 0; k < n-1; k++)
	for(int i = 0; i < m; i++){
		int x = u[i], y = v[i];
		if(d[x] < INF)
			d[y] = min(d[y], d[x]+w[i]);
	}

Floyd

(加边法)

const int INF = 100;
void Floyd(){
	int dist[MaxSize][MaxSize];
	string path[MaxSize][MaxSize];
	for(int i=0; i<vertexNum; i++)
		for(int j=0; j<vertexNum; j++){
			dist[i][j] = edge[i][j];
			if(dist[i][j] !=INF)
				path[i][j] = vertex[i] + vertex[j];
			else
				path[i][j] = "";
		}
	for(int k=0; k<vertexNum; k++)
		for(int i=0; i<vertexNum; i++)
			for(int j=0; j<vertexNum; j++)
				if(dist[i][k]+dist[k][j]<dist[i][j]){
					dist[i][j]=dist[i][k]+dist[k][j];
					psth[i][j]=path[i][k]+path[k][j];
				}
}

SPFA

  • 适用于含负权值的图
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
	final static int Max = 200010;
	final static int INF = 1<<30;
	
	static class edge{
		int to, next, w;
		public edge(int to, int next, int w) {
			// TODO Auto-generated constructor stub
			this.to = to;
			this.next = next;
			this.w = w;
		}
	}
	static edge e[] = new edge[Max];
	static int head[] = new int[Max];
	static int cnt = 0;
	
	static boolean vis[] = new boolean[Max];
	static int dis[] = new int[Max];
	

	private static void add(int from, int to, int w) {
		e[cnt] = new edge(to, head[from], w);
		head[from] = cnt++;
	}
	
	private static void spfa(int a) {
		Queue<Integer> q = new LinkedList<Integer>();
		
		dis[a] = 0;
		vis[a] = true;
		q.add(a);
		
		while(!q.isEmpty()) {
			int u = q.poll(), t;
			vis[u] = false;
			
			for(int i = head[u]; i != -1; i = e[i].next) {
				t = e[i].to;
				if(dis[t] > dis[u] + e[i].w && !vis[t]) {
					dis[t] = dis[u] + e[i].w;
					q.add(t);
					vis[t] = true;
				}
			}
		}
	}
		
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		int n,m;
		n = sc.nextInt();
		m = sc.nextInt();
		Arrays.fill(dis, INF);
		Arrays.fill(vis, false);
		Arrays.fill(head, -1);
		for(int i = 0; i < m; i++) {
			int u, v, l;
			u = sc.nextInt();
			v = sc.nextInt();
			l = sc.nextInt();
			add(u, v, l);
		}
		
		spfa(1);
		
		for(int i = 2; i <= n; i++)
			System.out.println(dis[i]);
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值