最短路算法

最短路算法

1.无负权边

这个一般用dijkstra,这个算法是可以计算单源最短路,时间复杂度为o(n^2),堆优化版的是(nlogn)的。先讲无的吧。

1.无负权边,用邻接矩阵存图,然后每一次找一个dis[i]最小的,用他来更新其他边,更行完之后再找一个dis[i]最小的

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+100;
#define inf 0x7fffffff
#define ll long long
ll edge[N][N],n,m,s,dis[N];
bool vis[N];
void dijkstra(int start){
for(int i=1;i<=n;i++) dis[i]=inf;//先初始化dis
dis[start]=0;
int now=start;
while(!vis[now]){
vis[now]=1;
for(int i=1;i<=n;i++){
dis[i]=min(dis[i],dis[now]+edge[now][i]);//利用现在最近的dis去更行其他dis这是所有最短路算法的和核心,压缩路径
}
int minn=inf;
for(int i=1;i<=n;i++){//更新完之后的最小dis
if((minn==inf||(dis[i]<minn))&&vis[i]==0){
minn=dis[i];
now=i;
}
}
}
}
int main(){
cin>>n>>m>>s;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
edge[i][j]=edge[j][i]=inf;//记得初始化
}
}
for(int i=1;i<=m;i++){
ll u,v,w;
cin>>u>>v>>w;
edge[u][v]=min(edge[u][v],w);
}
dijkstra(s);
for(int i=1;i<=n;i++){
cout<<dis[i]<<' ';
}
return 0;
}

 

2.用链式前向星存图,这个就是把寻找dis最小的点丢到了优先队列中使时间复杂度降到了o(mlogn)

#include<iostream>
#include<queue>
#include<bits/stdc++.h>
using namespace std;

int n,m,s;
long long head[100010],cnt,dis[100010];
bool vis[100010];//看是否已经确定了最大值
struct Edge{
long long to,dis,next;
}edge[200010];
struct node{
long long id,dis;
bool operator<(const node &x)const{
return x.dis<dis;
}
};

void add_edge(int from,int to,int dis){//链式前向星存图
edge[++cnt].to=to,
edge[cnt].dis=dis;
edge[cnt].next=head[from];
head[from]=cnt;
}
void dijkstra(int s){//堆优化
priority_queue<node>q;
for(int i=1;i<=n;i++) dis[i]=INT_MAX;
q.push({s,0});
dis[s]=0;
while(!q.empty()){
node a=q.top();
q.pop();
int now=a.id;
if(vis[now]) continue;
vis[now]=1;
for(int i=head[now];i;i=edge[i].next){
int j=edge[i].to;
if(dis[j]>dis[now]+edge[i].dis){
dis[j]=dis[now]+edge[i].dis;
if(vis[j]==0){
q.push({j,dis[j]});
}
}
}
}
}
int main(){
cin>>n>>m>>s;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
add_edge(u,v,w);
}
dijkstra(s);
for(int i=1;i<=n;i++){
cout<<dis[i]<<' ';
}
return 0;
}

 

2.存在负权边

这个用spfn,spfn就是用一个队列,每个在队列中的点去优化所有临近他的点知道队列为空,这个也可以判断负环,当从起点到这里经过了n个点时,他就形成了负环

#include<iostream>
#include<queue>
#include<bits/stdc++.h>
using namespace std;

int n,m,s;
long long head[100010],cnt,dis[100010],cnt1[100010];
bool vis[100010];//看是否已经确定了最大值
struct Edge{
long long to,dis,next;
}edge[500010];

void add_edge(int from,int to,int dis){
edge[++cnt].to=to,
edge[cnt].dis=dis;
edge[cnt].next=head[from];
head[from]=cnt;
}
bool spfa(int s){
queue<int>q;
for(int i=1;i<=n;i++) dis[i]=INT_MAX;
q.push(s);
vis[s]=1;//再队列中就为1
dis[s]=0;
while(!q.empty()){
int now=q.front();
q.pop();
vis[now]=0;
for(int i=head[now];i;i=edge[i].next){
long long j=edge[i].to;
if(dis[j]>dis[now]+edge[i].dis){
dis[j]=dis[now]+edge[i].dis;
if(vis[j]==0){//没在队列中才为1
cnt1[j]++;//这个数组就是判断是否有负环,每次如果更新就是有到起点的边加了一条,如果边数大于nl,那点就大于n+1了,就是不合法的              
if(cnt1[j]>=n) return false;
q.push(j);
vis[j]=1;
}
}
}
}
return true;
}
int main(){
cin>>n>>m>>s;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
add_edge(u,v,w);
}
bool flag=spfa(s);
if(flag){
for(int i=1;i<=n;i++) cout<<dis[i]<<' ' ;
}
else cout<<"no answer";
return 0;
}

 

3多源最短路

这个算法是Floyd算法,也是路径压缩和上面算法核心思想都是一样的。0(n^3)算法,能用极少

#include<iostream>
using namespace std;
#define inf 0x7fffffff
#define ll long long
ll n,m,s,edge[10001][10001];//邻接矩阵存图,O(n^2)对O(n^3)算法影响不大
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
if(k==i||edge[i][k]==inf)continue;//这是i->j经过k点,如果k点等于i或者k i之间无边的话可以直接忽略
for(int j=1;j<=n;j++){
edge[i][j]=min(edge[i][j],edge[i][k]+edge[k][j]);
}
}
}
}
int main(){
scanf("%d %d %d",&n,&m,&s);
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
edge[i][j]=edge[j][i]=inf;//初始化
}
}
for(int i=1;i<=m;i++){
ll u,v,w;
scanf("%d %d %d",&u,&v,&w);
edge[u][v]=min(edge[u][v],w);
}
floyd();
for(int i=1;i<=n;i++){
cout<<edge[s][i]<<" ";
}
return 0;
}
 
posted @ 2022-06-13 10:36  silky__player  阅读(53)  评论(0)    收藏  举报