当前位置: 首页 > article >正文

搜索与图论复习2最短路

单源最短路---所有边权是正数(Dijkstra算法O(n^2)--稠密图(邻接矩阵)和堆优化的Dijkstra算法O(mlogn)--稀疏图(邻接表)) 或存在负边权(Bellman-ford贝尔曼福特算法O(nm)和SPFA一般O(m) 最坏O(nm)  )

多源最短路---Floyd算法O(n^3)

一、迪杰斯特拉算法(Dijkstra):1dist[1]=0,dist[v]=正无穷。2for(v的0~n),s是当前已经确定最短路径的点,t是不在s中的距离最近的点,t放进s中,用t更新其他点的距离(dist[x]>dist[t]+w)更新。通过邻接矩阵存图。

#include<iostream>
#include<cstring> 
using namespace std;
const int N=510;
int n,m;
int g[N][N];
int dist[N];
bool st[N];//确定最短路 
int dijkstra(){
	memset(dist,0x3f,sizeof(dist));
	dist[1]=0;//起点 
	for(int i=0;i<n;i++){
		int t=-1;
		for(int j=1;j<=n;j++){
			if(!st[j]&&(t==-1||dist[t]>dist[j]))t=j;//找到dist最小的点 
		}
		if(t==n)break;//优化 
		st[t]=true;
		for(int j=1;j<=n;j++){
			dist[j]=min(dist[j],dist[t]+g[t][j]);
		}
	}
	if(dist[n]==0x3f3f3f3f)return -1;
	else return dist[n];
}
int main(){
	cin>>n>>m;
	memset(g,0x3f,sizeof(g));
	while(m--){
		int a,b,c;
		cin>>a>>b>>c;
		g[a][b]=min(g[a][b],c);
	}
	int t=dijkstra();
	cout<<t<<endl;
	
	return 0;
}

 

二、堆优化的迪杰斯特拉算法:优化在n个数中找距离最近的点O(n^2)用堆优化

#include<iostream>
#include<cstring> 
#include<queue> 
using namespace std;
typedef pair<int,int>PII;
const int N=150010;
int n,m;
int h[N],e[N],ne[N],idx,w[N];//权重 
int dist[N];
bool st[N];//是否已经确定最短路 
void add(int a,int b,int c){
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int dijkstra(){
	memset(dist,0x3f,sizeof(dist));
	dist[1]=0;//起点 
	priority_queue<PII,vector<PII>,greater<PII>>heap;
	heap.push({0,1});//从1点开始,0为距离 
	while(heap.size()){
		auto t=heap.top();
		heap.pop();
		int ver=t.second,distance=t.first;
		if(st[ver])continue;
		st[ver]=true; 
		for(int i=h[ver];i!=-1;i=ne[i]){
			int j=e[i];
			if(dist[j]>distance+w[i]){
				dist[j]=distance+w[i];
				heap.push({dist[j],j}); 
			}
		}
	}
	if(dist[n]==0x3f3f3f3f)return -1;
	else return dist[n];
}
int main(){
	cin>>n>>m;
	memset(h,-1,sizeof(h));
	while(m--){
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);
	}
	int t=dijkstra();
	cout<<t<<endl;
	
	return 0;
}

 

三、Bellman-Ford算法for循环n次,(备份)for所有边a,b,w表示所有a到b的边权值为w,(松弛),处理有福权边,能判断是否有负环(但是一般用SPFA做)

    • 第 k 次松弛:找到经过最多 k 条边的最短路径。

  • 通过多次松弛,算法可以逐步覆盖从起点到所有节点的所有可能路径

#include<iostream>
#include<cstring>
using namespace std;
const int N=510,M=10010;
int n,m,k;
int dist[N],backup[N];
struct Edge{
    int a,b,w;
}edges[M];
int bellman_ford(){
    memset(dist,0x3f,sizeof(dist));
    dist[1]=0;
    for(int i=0;i<k;i++){
        memcpy(backup,dist,sizeof(dist));
        for(int j=0;j<m;j++){
            int a=edges[j].a,b=edges[j].b,w=edges[j].w;
            dist[b]=min(dist[b],backup[a]+w);
        }
    }
    if(dist[n]>0x3f3f3f3f/2)return -0x3f3f3f3f;
    else return dist[n];
}
int main(){
    cin>>n>>m>>k;
    for(int i=0;i<m;i++){
        int a,b,c;
        cin>>a>>b>>c;
        edges[i]={a,b,c};
    }
    int t=bellman_ford();
    if(t==-0x3f3f3f3f)cout<<"impossible"<<endl;
    else cout<<t<<endl;
    return 0;
}

四、SPFA算法:用队列,只要有变小就取出队头,更新t的所有出边,成功就加入队列(更新过谁就拿谁来操作)通过队列优化 Bellman-Ford 算法,只对距离发生变化的节点进行松弛操作。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int n,m;
const int N=100010;
int dist[N];
bool st[N];
int h[N],e[N],ne[N],idx,w[N];
void add(int a,int b,int c){
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int spfa(){
    memset(dist,0x3f,sizeof(dist));
    dist[1]=0;
    queue<int>q;
    q.push(1);
    st[1]=true;
    while(q.size()){
        int t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(dist[j]>dist[t]+w[i]){
                dist[j]=dist[t]+w[i];
                if(!st[j]){
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    if(dist[n]==0x3f3f3f3f)return -0x3f3f3f3f;
    return dist[n];
}
int main(){
    cin>>n>>m;
    memset(h,-1,sizeof(h));
    while(m--){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    int t=spfa();
    if(t==-0x3f3f3f3f)cout<<"impossible"<<endl;
    else cout<<t<<endl;
    return 0;
}

补充负环判断:维护cnt[x]=cnt[t]+1,的数组,如果cnt[x]>=n存在负环。

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=2010,M=10010;
int h[N],e[M],ne[M],idx,w[M];
int dist[N],cnt[N];
bool st[N];
int n,m;
void add(int a,int b,int c){
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int spfa(){
    queue<int>q;
    for(int i=1;i<=n;i++){
        q.push(i);
        st[i]=true;
    }
    while(q.size()){
        int t=q.front();
        q.pop();
        st[t]=false;
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(dist[j]>dist[t]+w[i]){
                dist[j]=dist[t]+w[i];
                cnt[j]=cnt[t]+1;
                if(cnt[j]>=n)return true;
                if(!st[j]){
                    q.push(j);
                    st[j]=true;
                }
            }
        }
    }
    return false;
}
int main(){
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(false);
    cin>>n>>m;
    memset(h,-1,sizeof(h));
    while(m--){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    if(spfa())cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
    return 0;
}

五、Floyd算法:基于动态规划三层for枚举d(i,j)=min(d(i,j),d(i,k)+d(k,j))。

#include<iostream>
#include<cstring> 
using namespace std;
const int N=210,INF=1e9;
int n,m,Q;
int d[N][N];
void floyd(){
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
			}
		}
	}
}
int main(){
	cin>>n>>m>>Q;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)d[i][j]=0;
			else d[i][j]=INF;
		}
	}
	while(m--){
		int a,b,w;
		cin>>a>>b>>w;
		d[a][b]=min(d[a][b],w);
	}
	floyd();
	while(Q--){
		int a,b;
		cin>>a>>b;
		if(d[a][b]>INF/2)cout<<"impossible"<<endl;
		else cout<<d[a][b]<<endl;
	}
	return 0;
}

 


http://www.kler.cn/a/530377.html

相关文章:

  • 使用 PyTorch 实现逻辑回归并评估模型性能
  • PyCharm中使用Ollama安装和应用Deepseek R1模型:完整指南
  • tensorboard的基本使用及案例
  • TypeScript 运算符
  • 力扣257. 二叉树的所有路径(遍历思想解决)
  • 反射、枚举以及lambda表达式
  • 使用Z-score进行数据特征标准化
  • Rust 所有权特性详解
  • 谭浩强C语言程序设计(4) 8章(下)
  • Maven全解析:从基础到精通的实战指南
  • 利用DeepSeek提炼腾讯AI研究院的图景关键词——延伸畅想
  • Resnet 改进:尝试在不同位置加入Transform模块
  • LeetCode435周赛T2贪心
  • Elixir语言的安全开发
  • GWO优化LSBooST回归预测matlab
  • Java多线程与高并发专题——生产/消费者模式
  • XML DOM 节点树
  • ROS应用之AMCL 多机器人支持
  • Python-基于PyQt5,wordcloud,pillow,numpy,os,sys等的智能词云生成器(最终版)
  • C++编程语言:抽象机制:泛型编程(Bjarne Stroustrup)
  • 汇编语言运行环境搭建及简单使用
  • 沙皮狗为什么禁养?
  • 第39天:WEB攻防-通用漏洞_CSRF_SSRF_协议玩法_内网探针_漏洞利用
  • ubuntu 下使用deepseek
  • C# 装箱和拆箱(以及 as ,is)
  • gitea - fatal: Authentication failed