最短路径问题
求带权图中两点之间最短距离的问题
代码案例中的输入格式为
边数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;
}