2018年5月27號
阿新 • • 發佈:2018-05-28
下一個 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號