图论总结(6)最短路问题

最短路就是求图中两点的最短距离

最短路的算法这里写三种

一.Floyed-Warshall算法(O(N^3))

这是求最短路最简单的算法(求出所有点的最短路,适用于负权边,但不适用与负权回路)

int G[maxn][maxn],pre[maxn][maxn];
int n;
void print(int x,y){
	if(pre[x][y]==0)return;
	print(x,pre[x][y]);
	cout<<"->"<<y;
}
void floyed(){
	for(int k=1;k<=n;i++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			if(i!=j&&j!=k&&k!=j)
				if(d[i][j]>d[i][k]+d[k][j]){
					d[i][j]=d[i][k]+d[k][j];
					pre[i][j]=pre[k][j];
				}
}
邻接矩阵储存,pre记录路径,注意将d数组初始化为一个很大的数。

还可以用floyed来判断连通性。

void floyed(){
	for(int k=1;k<=n;i++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
			if(i!=j&&j!=k&&k!=j)
			d[i][j]=d[i][j]||(d[i][k]&&d[k][j]);
} 

二.Dijkstra(O(N^2))

单源最短路。

不能处理负权边。

算法原理就不讲了,教科书上有,直接上模板

(可以用优先队列优化,这里就不优化了)

int w[maxn][maxn],pre[maxn];
int n,s,e;
bool b[maxn],d[maxn];
void print(int x){
	if(pre[x]==0)return ;
	print(pre[x]);
	cout<<"->"<<x;
}
void Dijkstra(){
	memset(b,0,sizeof(b));
	for(int i=1;i<=n;i++)d[i]=INF;
	d[s]=0;
	for(int i=1;i<=n;i++){
		int minl=INF;
		int k=0;
		for(int j=1;j<=n;j++)
			if(!b[j]&&(d[j]<minl))
			{
				minl=d[j];
				k=j;
			}
		if(k==0)break;
		b[k]=true;
		for(int j=1;j<=n;j++)if(d[k]+w[k][j]<d[j]){
			d[j]=d[k]+w[k][j];
			pre[j]=k;
		}
	}
}

我反正一般不用Dijkstra算法,觉得BellmanFord更好,特别是优化了过后。

三.Bellman-Ford算法O(NE)

单源最短路 

可以处理负权边,不能处理负权回路。

直接给优化成SPFA常用的算法。

模板:

struct Edge{
	int from,to,dist;
	Edge(int f,int t,int d):from(f),to(t),dist(d){}
};
vector<Edge>edges;
vector<int>G[maxn];
int vis[maxn],d[maxn],cnt[maxn],pre[maxn],n;
void add_Edge(int f,int t,int d){
	edges.push_back(Edge(f,t,d));
	int m=edges.size();
	G[f].push_back(m-1);
}
bool Bellman_Ford(int s){
	queue<int>q;
	memset(cnt,0,sizeof(cnt));
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)d[i]=INF;
	d[s]=0;
	vis[s]=true;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		vis[u]=false;
		for(int i=0;i<G[u].size();i++){
			Edge& e=edges[G[u][i]];
			if(d[u]<INF&&d[e.to]>d[u]+e.dist){
				d[e.to]=d[u]+e.dist;
				pre[e.to]=G[u][i];
				if(!vis[e.to]){
					vis[e.to]=1;
					q.push(e.to);
					if(++cnt[e.to]>n)return false;
				}
			}
		}
	}
	return true;
}
用cnt数组判断是否有负权回路,应为每个点入队了n次时则有负权回路

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值