单源最短路

PS*1:关于SPFA——它已经死了(除了负权图)

PS*2:求最长路只需把权值变为相反数

PS*3:若要使A到B的单条路径权值最大值最小,二分答案(最大值),然后超过二分值的删边,判断是否连通。

 



dijkstra 模版:洛谷P4779

细节在代码中

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<queue>
using namespace std;
const long long MXN=5000000,INF=pow(2,50);
long long n,m,Sta;
//前向星 
struct Edge{
    long long v,w;
}edge[MXN];
long long last[MXN],nxt[MXN],en;
void AddEdge(long long u,long long v,long long w){
    edge[++en]=(Edge){v,w};
    nxt[en]=last[u];
    last[u]=en;
}
//优先队列Dij 
struct QElt{
    long long id,val;
    bool operator<(QElt x)const{return val>x.val;}//priority_queue默认大根对,所以重载 
};
long long dis[MXN];
void Dij(long long S){
    for(long long i=0;i<MXN;i++) dis[i]=INF;
    priority_queue<QElt>heap;
    heap.push((QElt){S,0});//加入起始点 
    dis[S]=0;
    while(!heap.empty()){
        QElt x=heap.top();heap.pop();
        long long u=x.id,val=x.val;
        if(dis[u]!=val) continue;//跳过废弃的堆元素 
        for(long long i=last[u];i!=0;i=nxt[i]){
            long long v=edge[i].v,w=edge[i].w;
            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                heap.push((QElt){v,dis[v]});
                //可能与堆中已有元素重复,所以前面写了个跳过的处理 
            }
        }
    }
}
int main(){
    cin>>n>>m>>Sta;
    en=0;for(long long i=0;i<MXN;i++) last[i]=0;
    for(long long i=1;i<=m;i++){
        long long u,v,w;scanf("%lld%lld%lld",&u,&v,&w);
        AddEdge(u,v,w);
    }
    Dij(Sta);
    for(long long i=1;i<=n;i++)
        printf("%lld ",dis[i]);
    return 0;
}
View Code(优先队列,new)

 

手写堆就大同小异啦

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<queue>
using namespace std;

const int MAXN=200005,MAXM=200005,INF=2147483647;

int n,m;

struct star {
    int u,v,w;
} edge[MAXM];
int last[MAXN],next[MAXM];

void addedge(int a,int b,int c) {
    m++;
    edge[m].u=a;
    edge[m].v=b;
    edge[m].w=c;
}
void starinit() {
    for(int i=1;i<=n;i++) last[i]=-1;
    for(int i=1; i<=m; i++) {
        int from=edge[i].u;
        next[i]=last[from];
        last[from]=i;
    }
}
struct nde {
    int id,val;
    bool operator <(nde qwq) const {
        return val>qwq.val;
    }
};

struct Heap {
    int size;
    nde tree[400005];

    void init() {
        size=0;
    }
    void push(nde input) {
        size++;
        tree[size]=input;
        for(int i=size; i>1;) {//防越界 
            if(tree[i].val<tree[i/2].val) {//判断与父节点关系 
                swap(tree[i],tree[i/2]);
                i=i/2;
            } else break;
        }
    }
    void pop() {
        tree[1]=tree[size];
        size--;
        for(int i=1; i*2<=size;) {//防越界 
            int a=tree[i].val,b=tree[i*2].val,c=tree[i*2+1].val;
            if(i*2+1>size) {//无右子树情况 
                if(a>b) swap(tree[i],tree[i*2]);
                break;
            } else {
                if(a>b||a>c){
                    if(b<c){//判断两颗子树大小关系 
                        swap(tree[i],tree[i*2]);//左子树 
                        i=i*2;
                    }else{
                        swap(tree[i],tree[i*2+1]);//右子树 
                        i=i*2+1;
                    }
                } else break;//比所有子树的值都小 
            }
        }
    }
    nde top() {
        return tree[1];
    }
}heap;

int dis[MAXN];
void dij(int sta) {
    for(int i=1;i<=n;i++) dis[i]=INF;
    dis[sta]=0;
    heap.init();
    heap.push((nde){sta,0});
    for(;heap.size>0;){
        int now=heap.top().id;
        int dv=heap.top().val;
        heap.pop();
        if(dv!=dis[now]) continue;//判断是否已经被废弃 
        for(int i=last[now];i!=-1;i=next[i]){
            int to=edge[i].v;
            int val=edge[i].w;
            if(dis[to]>dis[now]+val){
                dis[to]=dis[now]+val;
                heap.push((nde){to,dis[to]});
            }
        }
    }
}
int main() {
    int cirno,baka;
    cin>>n>>cirno>>baka;
    m=0;
    for(int i=1; i<=cirno; i++) {
        int t1,t2,t3;
        scanf("%d%d%d",&t1,&t2,&t3);
        addedge(t1,t2,t3);
    }
    starinit();
    dij(baka);
    for(int i=1;i<=n;i++){
        printf("%d ",dis[i]);
    }
    return 0;
}
View Code(堆优化)

 


 

SPFA Bellman-Ford的队列优化 模版:洛谷P3371

 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<queue>
using namespace std;
const int PTN=20000,EDN=1000000,INF=999999999;
int n,m,Sta;
struct Edge{
    int v,w;
}edge[EDN];
int last[PTN],nxt[EDN],en;
void AddEdge(int u,int v,int w){
    edge[++en]=(Edge){v,w};
    nxt[en]=last[u];
    last[u]=en;
}
int que[EDN*5],isq[PTN],head,tail;
int dis[PTN];
void SPFA(int S){
    for(int i=0;i<PTN;i++) isq[i]=0,dis[i]=INF;
    head=tail=0;
    que[tail++]=S;
    isq[S]=1;dis[S]=0;
    while(head<tail){
        int u=que[head++];
        for(int i=last[u];i!=0;i=nxt[i]){
            int v=edge[i].v,w=edge[i].w;
            if(dis[v]>dis[u]+w){
                dis[v]=dis[u]+w;
                if(!isq[v]) que[tail++]=v,isq[v]=1;
            }
        }
        isq[u]=0;
    }
}
int main(){
    cin>>n>>m>>Sta;
    en=0;for(int i=0;i<=n;i++) last[i]=0;
    for(int i=1;i<=m;i++){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        AddEdge(u,v,w);
    }
    SPFA(Sta);
    for(int i=1;i<=n;i++) 
        if(dis[i]>=INF) printf("2147483647 ");
        else printf("%d ",dis[i]);
    return 0;
}
View Code(普通,new)

 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;

const int INF=2147483647;

int n,m,s,e;

struct star{//前向星 
    int u,v,w;
}edge[500005];
int front[500005],size[500005];

void addedge(int a,int b,int c){
    m++;
    edge[m].u=a;
    edge[m].v=b;
    edge[m].w=c;
}
bool starcmp(star a,star b){
    if(a.u<b.u) return 1;
    else if(a.u>b.u) return 0;
    else return a.v<b.v;
}
void starinit(){
    sort(edge+1,edge+1+m,starcmp);
    int flag=-1;
    for(int i=1;i<=m;i++){
        if(flag!=edge[i].u){
            flag=edge[i].u;
            front[flag]=i;
        }
        size[flag]++;
    }
}
int dis[500005];
int isq[500005];
int que[500005];
int book[500005];
int jl[500005];
bool spfa(int sta){
    for(int i=1;i<=n;i++){dis[i]=INF;isq[i]=0;}
    dis[sta]=0;
    int head=0,tail=0;
    isq[sta]=1;
    que[tail]=sta;
    tail++;
    for(;head<tail;){
        int now=que[head],to;
        isq[now]=0;
        for(int i=front[now];i<front[now]+size[now];i++){
            to=edge[i].v;
            if(dis[to]>dis[now]+edge[i].w){
                dis[to]=dis[now]+edge[i].w;
                jl[to]=now;//记录路径 
                book[to]++;
                if(book[to]>n){
                    return 0;//负环 
                }
                if(isq[to]==0){//小优化,若已在队列中,就不再加入 
                    isq[to]=1;
                    que[tail]=to;
                    tail++;
                }
            }
        }
        head++;
    }
    return 1;//正常返回 
}
int path[500005],plen;
void getpath(){
    plen=1;
    int np=e;
    for(;;plen++){
        path[plen]=np;
        if(np==s){
            break;
        }
        np=jl[np];
    }
    for(int i=1;i<=plen/2;i++){
        swap(path[i],path[plen-i+1]);
    }
}
int main(){
    int cirno;
    cin>>n>>cirno>>s>>e;//n个点,m条边,s为起点,e为终点的最短路 
    m=0;
    for(int i=1;i<=cirno;i++){
        int t1,t2,t3;
        scanf("%d%d%d",&t1,&t2,&t3);
        addedge(t1,t2,t3);
    }
    starinit();
    if(spfa(s)==0){
        cout<<"Error map!";
        return 0;
    }
    cout<<dis[e]<<endl;
    getpath();
    for(int i=1;i<=plen;i++){
        printf("%d ",path[i]);
    }
    return 0;
}
View Code(含判负环&路径输出)

 

转载于:https://www.cnblogs.com/sun123zxy/p/shortestpath.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值