图论最短路模板

14 篇文章 0 订阅
2 篇文章 0 订阅

最短路模板

floyed

核心思想 : 在两点间不断插入其他点看是否可以让最短距离变小

int dis[maxn][maxn];
int path[maxn][maxn];
void floyed(){

    for(int i=1;i<=n;i++){//初始化
        for(int j=1;j<=n;j++){
            dis[i][j]=1e9;
            if(i==j) dis[i][j]=0;
        }
    }
    
    for(int i=1,a,b,cost;i<=m;i++){
        cin>>a>>b>>cost;
        dis[a][b]=dis[b][a]=cost;
        path[a][b]=b;
        path[b][a]=a;
    }
	//核心代码
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if( dis[i][j]>dis[i][k]+dis[k][j] ){
                    dis[i][j]=dis[i][k]+dis[k][j];
                    path[i][j]=path[i][k];//路径
                }else if(dis[i][j]==dis[i][k]+dis[k][j]+b[k] && path[i][j]>path[i][k]){//字典序最小路径
                    path[i][j]=path[i][k];
                }
            }
        }
    }
	//路径打印    
    int s,g;
    for(int i=s;i!=g;i=path[i][g])
        printf("%d ",i);
    printf("%d",g);

}

Dijkstra

核心思想 : 不断从未选顶点集合选取到已选顶点集合的最短距离边

#define rep(x,y,z) for(int x = y; x<=z;++x)
struct cpp{
    int to,cost;
}tem;
bool vis[10005];
int dis[10005];//最短距离
int path[10005];//path表示起点到i点路径的上要走的i的前一个点
priority_queue<cpp> dui;
bool operator<(const cpp&a,const cpp&b){
    return a.cost>b.cost;
}
vector<cpp> g[10005];
int n,s;
void Dijkstra(){
    rep(i,1,n) dis[i]=1e9;
    dis[s]=0;
    tem.cost=0;tem.to=s;
    dui.push(tem);
    int u;
    while(!dui.empty()){
        u=dui.top().to;
        dui.pop();
        if(vis[u]) continue;
        vis[u]=1;
        rep(i,0, (int)(g[u].size()-1) ){
            if( vis[g[u][i].to]==0&&dis[g[u][i].to]>dis[u]+g[u][i].cost ){
                dis[g[u][i].to]=dis[u]+g[u][i].cost;
                path[g[u][i].to]=u;//更新路径
                tem.to=g[u][i].to;tem.cost=dis[g[u][i].to];
                dui.push(tem);
            }
        }
    }
}

void print_path(int ed){
    stack<int> mystack;
    mystack.push(ed);
    while(ed!=s){
        ed=path[ed];
        mystack.push(ed);
    }
    while(!mystack.empty()){
        cout<<mystack.top()<<" ";
        mystack.pop();
    }
    putchar('\n');
}

Bellman_ford

核心思想 : 俩点之间最多有n-1条边,不断进行松弛操作

#define rep(x,y,z) for(int x = y; x<=z;++x)
struct cpp{
    int from,to,cost;//如果是无向图,记得存from和to交换位置再存一遍
}edge[500005];
int dis[10005];
int path[10005];//路径打印
int n,s,m;
void Bellman_ford(){
    rep(i,1,n) dis[i]=1e9;
    dis[s]=0;
    bool flag;
    rep(i,1,n-1){
        flag=1;
        rep(j,1,m){
            if(dis[edge[j].to]>dis[edge[j].from]+edge[j].cost){
                dis[edge[j].to]=dis[edge[j].from]+edge[j].cost;
                path[edge[j].to]=edge[j].from;//更新路径
                flag=0;
            }
        }
        if(flag) break;
    }
}
void print_path(int ed){//打印路径
    stack<int> mystack;
    mystack.push(ed);
    while(ed!=s){
        ed=path[ed];
        mystack.push(ed);
    }
    while(!mystack.empty()){
        cout<<mystack.top()<<" ";
        mystack.pop();
    }
    putchar('\n');
}

SPFA

核心思想 : 像Bellman_ford一样不断松弛,但是优先选择被松弛的点进行松弛

#define rep(x,y,z) for(int x = y; x<=z;++x)
int n,s;
int dis[10005];
int path[10005];
bool vis[10005];
struct cpp{
    int to,cost;
}tem;
vector<cpp> g[10005];
queue<int> dui;

void SPFA(){
    repi(i,1,n) dis[i]=2147483647;
    dis[s]=0; vis[s]=1; dui.push(s);
    while(!dui.empty() ){
        int x=dui.front();dui.pop();
        vis[x]=0;
        repi(i,0, (int) (g[x].size()-1) ){
            if( dis[ g[x][i].to ]>dis[ x ] + g[x][i].cost ){
                dis[ g[x][i].to ]=dis[ x ] + g[x][i].cost;
                path[ g[x][i].to ]=x;//更新路径
                if(vis[ g[x][i].to ]==0){
                    vis[ g[x][i].to ]=1;
                    dui.push(g[x][i].to);
                }
            }
        }
    }
}
void print_path(int ed){//打印路径
    stack<int> mystack;
    mystack.push(ed);
    while(ed!=s){
        ed=path[ed];
        mystack.push(ed);
    }
    while(!mystack.empty()){
        cout<<mystack.top()<<" ";
        mystack.pop();
    }
    putchar('\n');
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值