1. 程式人生 > 其它 >最短路模板

最短路模板

1.dijkstra演算法:

從一點開始,更新所能到達的點的最小值,不能判斷有負權值的圖

模板:(與Prime演算法基本相同)

void dij(){//堆優化模板
  priority_queue<pll,vector<pll>,greater<pll>> q;
  memset(dis,0x3f,sizeof(dis));
  memset(vis,0,sizeof(vis));
  q.push({0,1});
  dis[1]=0;
  while(!q.empty()){
    ll u=q.top().first;ll v=q.top().second;
    q.pop();
    
if(vis[v]) continue; vis[v]=1; for(int i=head[v];i;i=e[i].next){ ll t=e[i].to; if(dis[t]>u+e[i].w){ dis[t]=u+e[i].w;q.push({dis[t],t}); } } } }

2.bellman-ford演算法:

就是一種遍歷,每條邊都要跑n次,最後再判斷能不能繼續鬆弛,能得話,說明有負權值邊。

模板:

ll bellman(){
  memset(dis,0x3f,sizeof(dis));
  dis[
1]=0; for(int i=1;i<=n;i++){ for(int j=1;j<=cnt;j++){ if(dis[e[j].y]>dis[e[j].x]+e[j].w){ dis[e[j].y]=dis[e[j].x]+e[j].w; } } } for(int i=1;i<=cnt;i++){//繼續鬆弛,判斷有無負邊 if(dis[e[i].y]>dis[e[i].x]+e[i].w) return 1; } return 0; }

3 spfa演算法:

是bellman_ford的優化版本,bellman_ford演算法中,當某些點已經找到最短路時,就不需要再遍歷鬆弛,就可以省掉這一部分,保證每次都鬆弛沒有找到最短路的點。

判斷是否有負權值,有負權值,就可以無限鬆弛,正常情況下一個圖點數為n,它的鬆弛次數應為n-1,所以當  n(鬆弛次數)>=n-1時就證明有負權值

模板:

void spfa()
  memset(dis,0x3f,sizeof(dis));
  memset(vis,0,sizeof(vis));
  dis[1]=0;
  queue<ll> q;
  q.push(1);
  vis[1]=1;
  while(!q.empty()){
    ll t=q.front();
    q.pop();
    vis[t]=0;
    for(ll i=head[t];i;i=e[i].next){
      ll j=e[i].to;
      if(dis[j]>dis[t]+e[i].w){
        dis[j]=dis[t]+e[i].w;
        if(!vis[1]){
          q.push(j);vis[j]=1;
        }
      }
    }
  }
}

spfa判斷負環時:

ll spfa(){
  memset(dis,0x3f,sizeof(dis));
  memset(vis,0,sizeof(vis));
  memset(num,0,sizeof(num));
  dis[1]=0;
  queue<ll> q;
  for(ll i=1;i<=n;i++){
    q.push(i);vis[i]=1;
  }//將所有點一次性存入和單獨將1存入都可以,前者快些
  while(!q.empty()){
    ll t=q.front();
    q.pop();
    vis[t]=0;
    for(ll i=head[t];i;i=e[i].next){
      ll j=e[i].to;
      if(dis[j]>dis[t]+e[i].w){
        num[j]=num[t]+1;
        if(num[j]>=n) return 1;//判斷鬆弛次數是否>=n
        dis[j]=dis[t]+e[i].w;
        if(!vis[j]){
          q.push(j);vis[j]=1;
        }
      }
    }
  }
  return 0;
}