最短路径记录

本文详细介绍了四种图论算法:Dijkstra的堆优化实现,解决最短路径问题;BF算法,即广度优先搜索;SPFA算法,BF的优化版,同样用于寻找最短路径;以及Floyd算法,通过三重循环求解最短路径动态规划。这些算法在稀疏图和稠密图中各有应用,对于理解和解决图的最短路径问题具有重要意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

dijkstra 堆优化

这是一个稀疏图,所以选择堆优化,稀疏的意思是,点多边也多,所以稀疏
使用堆进行选择
PII vector greater

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const int N = 1e5+10;
vector<pair<int,int>> v[N];
typedef pair<int,int> PII;
int dist[N];
int n,m;
int INF = 0x3f3f3f3f;
bool st[N];

int dijkstra(){
    priority_queue<PII,vector<PII>,greater<PII>> heap;//first 距离 second 点
    heap.push({0,1});
    while(heap.size()){
        auto t = heap.top();
        heap.pop();
        int ver = t.second,distance = t.first;
        if(st[ver]) continue;
        st[t.second] = 1;
        for(auto i:v[ver]){
            int tmp = i.first;
            if(dist[tmp] > distance + i.second){
                dist[tmp] = distance + i.second;
                heap.push({dist[tmp],tmp});
            }
        }
    }

    if(dist[n]!=INF)
        return dist[n];
    else
        return -1;
}

int main() {
    cin>>n>>m;
    for(int i = 0; i<m;i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        v[a].push_back({b,c});
    }
    memset(dist,INF,sizeof dist);
    dist[1] = 0;
    int res = dijkstra();
    cout<<res;
    return 0;
}

BF算法

#include <iostream>
#include <cstring>
using namespace std;
const int N = 1e4+10,INF = 0x3f3f3f3f;

struct edge{
    int a,b,c;
}e[N];
int dist[505],back_up[505];
int n,m,k;
void bf(){

    for(int i = 0;i<k;i++){
        memcpy(back_up,dist,sizeof dist);
        for(int j = 0;j < m;j++) {
            int a = e[j].a,b = e[j].b,c = e[j].c;
            dist[b] = min(dist[b],back_up[a]+c);
        }
    }
}
int main() {
    cin>>n>>m>>k;
    memset(dist,INF,sizeof dist);
    for(int i = 0;i<m;i++){
        scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
    }
    dist[1] = 0;
    bf();
    if(dist[n]>=INF/2){
        cout<<"impossible";
    }
    else
        cout<<dist[n];
    return 0;
}

SPFA算法 BF算法的优化

也可以用来测正权图,类似dijkstra 具体思想就是每次去修改自己的邻接边,如果可以改就改 改一直到队列为空即可

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const int N = 1e5+10,INF = 0x3f3f3f3f;
int n,m;
typedef pair<int,int> PII;
vector<PII> tu[N];
int dist[N];
bool st[N];
queue<int> q;
int spfa(){
    dist[1] = 0;
    q.push(1);
    st[1] = 1;
    while(!q.empty()){
        int t = q.front();
        st[t] = 0;
        q.pop();
        for(auto i:tu[t]){
            int b = i.first,w = i.second;
            if(dist[b]>dist[t]+w)
            {
                dist[b] = dist[t] +w;
                if(!st[b]){
                    q.push(b);
                    st[b] = 1;
                }
            }
        }
    }

    if(dist[n]==INF){
        return -INF;
    }else {
        return dist[n];
    }
}


int main() {
    cin>>n>>m;
    for(int i = 0;i<m;i++){
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        tu[a].push_back({b,w});
    }
    memset(dist,INF, sizeof dist);

    int res = spfa();
    if(res == -INF)
        cout<<"impossible";
    else
        cout<<res;
    return 0;
}

spfa判断负环
需要注意 要把所有的点都放到队列里面,然后再去找cnt大于等于n的点

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1e5+10,INF = 0x3f3f3f3f;
typedef pair<int,int> PII;
vector<PII> v[N];
queue<int> q;
int dist[N];
int cnt[N];//用于判断负环新增的
int n,m;
int st[N];
int spfa(){
    for(int i = 1;i<=n;i++){
        q.push(i);
        st[i] = 1;
    }
    while(!q.empty()){
        int t = q.front();
        q.pop();
        st[t] = 0;
        for(auto i:v[t]){
            int b = i.first;
            int w = i.second;
            if(dist[b]>dist[t]+w){
                dist[b] = dist[t] +w;
                cnt[b] = cnt[t]+1;
                if(cnt[b] >= n) return -1;
                if(!st[b]){
                    q.push(b);
                    st[b] = 1;
                }
            }
        }
    }
    return 0;
}
int main() {
    cin>>n>>m;
    for(int i = 0;i<m;i++){
        int a,b,w;
        scanf("%d%d%d",&a,&b,&w);
        v[a].push_back({b,w});
    }
    memset(dist,INF,sizeof dist);
    int res = spfa();
    if(res == -1){
        cout<<"Yes";
    }
    else
        puts("No");

    return 0;
}

floyd
三重循环求值 动态规划

#include <iostream>
using namespace std;
const int N = 205,INF = 1e9;
int n,m,q;

int d[N][N];
void folyed(){
    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() {
    scanf("%d%d%d",&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;
        scanf("%d%d%d",&a,&b,&w);
        d[a][b] = min(d[a][b],w);
    }

    folyed();

    while(q--){
        int a,b;
        scanf("%d%d",&a,&b);
        if(d[a][b]>=INF/2)
            printf("impossible\n");
        else
            printf("%d\n",d[a][b]);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值