1. 程式人生 > >2018年5月27號

2018年5月27號

下一個 info 今天 IV span https 負環 class 第一篇

  一開始並不懂得真正判斷負環,自從寫了這道題才有點感覺:這道題就是洛谷的p1768天路。

  我主要想說如何判斷負環:

  首先一個最普通的做法:

 1 void spfa(int x)
 2 {
 3     vis[x]=true;
 4     for(int i=head[x];i;i=e[i].next)
 5     {
 6         if(dis[e[i].to]>dis[x]+e[i].dis)
 7         {
 8             cnt++;
 9             if(cnt>=n)
10             {
11                 flag=1
; 12   return ; 13 } 14 dis[e[i].to]=dis[x]+e[i].dis; 15 spfa(e[i].to); 16 } 17 } 18 vis[x]=false; 19 }

就是在做spfa的同時進行cnt++;利用cnt這個計數器來計算apfa的次數,如果次數大於等於了數的總數n;那麽說明這個spfa做到了下一個輪回,這就說明碰到了負環;那麽就可以結束循環,做個標記,輸出出現負環的提示。

  接下來再使計數器優化一下,看書之後就有了這樣做法:

 1 void spfa(int x)
 2 {
 3     vis[x]=true;
 4     for(int i=head[x];i;i=e[i].next)
 5     {
 6         if(dis[e[i].to]>dis[x]+e[i].dis)
 7         {
 8             pd[e[i].to]=pd[x]+1;//只是這裏改變了一下,由cnt改成數組存;
 9             if(e[i].to>=n)
10             {
11                 flag=1;
12                 return
; 13 } 14 dis[e[i].to]=dis[x]+e[i].dis; 15 spfa(e[i].to); 16 } 17 } 18 vis[x]=false; 19 }

其實這個代碼跟上面一個差不多技術分享圖片

就是將spfa函數裏的cnt計時器改成數組來存,這樣邊存入邊計算,使時間節省很多,入過你TLE了可以使用這種方法;反正我屢用不爽技術分享圖片

  還有一種會比較高級,一開始我也沒有反應過來(據說時間更快,不過我沒有用它和第二個做實驗),但蒟蒻的我沒有反應過來

話不多說 呈上代碼:

 1 bool zx(int x,double nj)
 2 {
 3     vis[x]=1;
 4     for(int i=h[x];i;i=e[i].nx)
 5     {
 6         double p=1.0*e[i].p*nj-1.0*e[i].v;
 7         if(p+ans[x]<ans[e[i].to])
 8         {
 9             ans[e[i].to]=p+ans[x];
10             if(vis[e[i].to]||zx(e[i].to,nj))//就這個zx(e[i].to,nj),利用了深搜來解決一切
11             {
12                 vis[e[i].to]=0;
13                 return 1;
14             }
15         }
16     }
17     vis[x]=0;
18     return 0;
19 }

其實這點還好理解,及你有許多的數時,做起這個spfa時,zx(e[i].to,nj)不停的做如果值變成了負數,就說明碰到了負環;同時可以用草稿本算一遍,你就可以立刻明白;

  今天就說到這,這是我第一篇博客(請各位看官賞個臉技術分享圖片

2018年5月27號