最短路径——DFS、Dijkstra、Floyd、Bellman-Ford、spfa

最短路径问题

求带权图中两点之间最短距离的问题
代码案例中的输入格式为

边数M 结点数N
边1的起始节点 边1的目的结点 边1的权重

边M的起始节点 边M的目的结点 边M的权重

5 5
1 2 20
2 3 30
3 4 20
4 5 20
1 5 100

题目:https://vjudge.net/problem/POJ-2387

DFS

原理:从源节点深度搜索最短路径

/*
* problem:最短路径
* method:dfs
* date:2020/08/12
*/
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<utility>
#include<cmath>
#define ll long long
using namespace std;
const int inf=1e10;
const int maxn=1005;
int arc[maxn][maxn];
bool vis[maxn];
int mini;
int T,N,start,dest;
void init() {
	int i,j;
	for(i=0; i<N; i++) {
		for(j=0; j<N; j++) {
			if(i==j) arc[i][j]=0;
			else arc[i][j]=inf;
		}
		vis[i]=false;
	}
	mini=inf;
}
void dfs(int index,int minDis) {
	int i,j;
	if(index==dest) {
		mini=mini<minDis?mini:minDis;
		return;
	}
	if(minDis>mini) return;
	for(i=0; i<N; i++) {
		if(!vis[i]&&arc[index][i]!=inf) {
			vis[i]=true;
			dfs(i,minDis+arc[index][i]);
			vis[i]=false;
		}
	}
}
using namespace std;
int main() {
	int i,j;
	while(cin>>T>>N) {
		init();
		int a,b,c;
		for(i=0; i<T; i++) {
			cin>>a>>b>>c;
			a--;
			b--;
			if(arc[a][b]>c) {
				arc[a][b]=arc[b][a]=c;
			}
		}
		start=N-1;
		dest=0;
		vis[start]=true;
		dfs(start,0);
		cout<<mini<<endl;
	}
	return 0;
}

Dijkstra

原理:从源节点开始更新到可达结点的最短距离,贪心选择下一个结点进行更新

/*
* problem: 最短路径
* method:dijkstra
* date:2020/08/12
*/
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<utility>
#include<cmath>
#define ll long long
using namespace std;
const int inf=1e9;
const int maxn=2005;
int arc[maxn][maxn];
bool vis[maxn];
int dis[maxn];
int T,N,start,dest;
void init() {
	int i,j;
	for(i=0; i<N; i++) {
		for(j=0; j<N; j++) {
			if(i==j) arc[i][j]=0;
			else arc[i][j]=inf;
		}
		vis[i]=false;
		dis[i]=inf;
	}
}
void dijkstra(int u) {
	int i,j;
	dis[u]=0;
	int min;
	for(i=0; i<N; i++) {
		min=inf;
		for(j=0; j<N; j++) {
			if(!vis[j]&&dis[j]<min) {
				u=j;
				min=dis[j];
			}
		}
		vis[u]=true;
		for(j=0; j<N; j++) {
			if(!vis[j]&&arc[u][j]!=inf&&dis[u]+arc[u][j]<dis[j]) {
				dis[j]=dis[u]+arc[u][j];
			}
		}
	}
}
int main() {
	int i,j;
	while(cin>>T>>N) {
		init();
		int a,b,c;
		for(i=0; i<T; i++) {
			cin>>a>>b>>c;
			a--;
			b--;
			if(arc[a][b]>c) {
				arc[a][b]=arc[b][a]=c;
			}
		}
		start=N-1;
		dest=0;
		dijkstra(start);
		cout<<dis[dest]<<endl;
	}
	return 0;
}

floyd

原理:从0-N-1考虑两点间经过的结点数来确定两点间最短距离,最终求出了任意两点间距离

/*
* problem:最短路径
* method:floyd
* date:2020/08/12
*/
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<utility>
#include<cmath>
#define ll long long
using namespace std;
const int inf=1e9;
const int maxn=2005;
int arc[maxn][maxn];
int T,N,start,dest;
void init() {
	int i,j;
	for(i=0; i<N; i++) {
		for(j=0; j<N; j++) {
			if(i==j) arc[i][j]=0;
			else arc[i][j]=inf;
		}
	}
}
int main() {
	int i,j;
	while(cin>>T>>N) {
		init();
		int a,b,c;
		for(i=0; i<T; i++) {
			cin>>a>>b>>c;
			a--;
			b--;
			if(arc[a][b]>c) {
				arc[a][b]=arc[b][a]=c;
			}
		}
		for(int k=0; k<N; k++) {
			for(i=0; i<N; i++) {
				for(j=0; j<N; j++) {
					if(arc[i][k]+arc[k][j]<arc[i][j]) {
						arc[i][j]=arc[i][k]+arc[k][j];
					}
				}
			}
		}
		start=N-1;dest=0;
		cout<<arc[start][dest]<<endl;
	}
	return 0;
}

bellman_ford

原理:从两点间距离看是遍历松弛两点间的距离,从点的角度看类似于广度优先搜索的dijkstra(dijkstra类似于深度优先搜索)

/*
* problem:最短路径
* method:bellman_ford
* date:2020/08/12
*/
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<utility>
#include<cmath>
#define ll long long
using namespace std;
const int inf=1e9;
const int maxn=1005;
const int maxm=4005;
struct Edge {
	int u,v,w;
};
Edge e[maxm];
int dis[maxn];
int M,N,start,dest;
bool bellman_ford(int start) {
	int i,j;
	for(i=0; i<N; i++) {
		dis[i]=inf;
	}
	dis[start]=0;
	bool flag=false;
	for(i=0; i<N-1; i++) {
		flag=false;
		for(j=0; j<M; j++) {
			if(dis[e[j].v]>dis[e[j].u]+e[j].w) {
				dis[e[j].v]=dis[e[j].u]+e[j].w;
				flag=true;
			}
		}
		if(!flag) break;
	}
	for(i=0; i<M; i++) {
		if(dis[e[i].u]>dis[e[i].v]+e[i].w) {
			return false;
		}
	}
	return true;
}
int main() {
	int i,j;
	while(cin>>M>>N) {
		int a,b,c;
		for(i=0; i<M; i++) {
			cin>>a>>b>>c;
			a--;
			b--;
			e[i].u=a;
			e[i].v=b;
			e[i].w=c;
			e[i+M].v=a;
			e[i+M].u=b;
			e[i+M].w=c;
		}
		M*=2;	//无向图边数需乘以2
		start=N-1;
		dest=0;
		if(bellman_ford(start) ) {
			cout<<dis[dest]<<endl;
		} else {
			cout<<"存在负权回路"<<endl;
		}
	}
	return 0;
}

spfa

原理:采用队列来对bellman-ford进行改进

/*
* problem:最短路径
* method:spfa
* date:2020/08/12
*/
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<utility>
#include<cmath>
#define ll long long
using namespace std;
const int inf=1e10;
const int maxn=1005;
vector<int> to[maxn],weight[maxn];
bool vis[maxn];
int dis[maxn];
int T,N,start,dest;
void spfa(int start){
	int i,j;
	for(i=0;i<N;i++){
		dis[i]=inf;
		vis[i]=false;
	}
	dis[start]=0;
	vis[start]=true;
	queue<int> Q;
	Q.push(start);
	while(!Q.empty()){
		int u=Q.front();
		Q.pop();
		vis[u]=false;
		for(i=0;i<to[u].size();i++){
			int v=to[u][i],w=weight[u][i];
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				if(!vis[v]){
					vis[v]=true;
					Q.push(v);
				}
			}
		}
	}
}
int main(){
	int i,j;
	while(cin>>T>>N){
		int a,b,c;
		for(i=0;i<T;i++){
			cin>>a>>b>>c;
			a--;b--;
			to[a].push_back(b);
			weight[a].push_back(c);
			//无向图
			to[b].push_back(a);
			weight[b].push_back(c);
		}
		start=N-1;
		dest=0;
		spfa(start);
		cout<<dis[dest]<<endl;
	}
	return 0;
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值