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; }
手写堆就大同小异啦
#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; }
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; }
#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; }