[USACO06DEC]虫洞Wormholes (负环模板)
题意::问一个图是否存在负环,虫洞一边的权值为负
思路:
dfs版spfa判环根据:若一个节点出现2次及以上,则存在负环.(你可以假想一下,当一个点被搜过时,再次深搜的话还能搜索到那不就说明存在负环嘛可能解释的不好,请见谅)
{补充bfs版本:若一个节点入队列的次数超过n,则存在负环.}
如果是bfs来实现的话,果断到达上限(T-L-E),而dfs版的话,就相对快一些.
对于本题的强大数据来说,还需加入一定的优化:
由于是负环,所以无需像一般的spfa一样初始化为极大的数,只需要初始化为0就够了(可以减少大量的搜索,但要注意最开始时for一遍)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=505; 5 int inf=0xfffffff; 6 int dis[maxn]; 7 bool ant[maxn]; 8 int n,m,w,flag; 9 struct node 10 { 11 int to,val; 12 node(){} 13 node(int xx,int yy):to(xx),val(yy){} 14 }; 15 vector<node> v[maxn];//本人喜欢用邻接表 16 void init() 17 { 18 for(int i=1;i<=n;i++) 19 { 20 v[i].clear(); 21 dis[i]=0; 22 ant[i]=0; 23 } 24 } 25 void dfs_spfa(int x) 26 { 27 if(ant[x]){//只要有一个点走过两次说明存在负环,即可退出,并释放标记 28 ant[x]=0; 29 flag=1; 30 return ; 31 } 32 ant[x]=1;//标记表示走过 33 for(int i=0;i<v[x].size();i++) 34 { 35 node p=v[x][i]; 36 if(dis[p.to]>dis[x]+p.val){ 37 dis[p.to]=dis[x]+p.val; 38 dfs_spfa(p.to); 39 if(flag==1){ 40 ant[x]=0;return ;//存在负环的话就层层退出 41 } 42 } 43 } 44 ant[x]=0;//再次释放标记 45 } 46 int main() 47 { 48 int t; 49 scanf("%d",&t); 50 while(t--) 51 { 52 scanf("%d%d%d",&n,&m,&w); 53 init(); 54 for(int i=1;i<=m;i++) 55 { 56 int a,b,c; 57 scanf("%d%d%d",&a,&b,&c); 58 v[a].push_back(node(b,c)); 59 v[b].push_back(node(a,c)); 60 } 61 for(int i=1;i<=w;i++) 62 { 63 int a,b,c; 64 scanf("%d%d%d",&a,&b,&c); 65 v[a].push_back(node(b,-c)); 66 } 67 flag=0; 68 for(int i=1;i<=n;i++) 69 { 70 dfs_spfa(i); 71 if(flag){break;} 72 } 73 if(flag){ 74 cout<<"YES"<<endl; 75 } 76 else{ 77 cout<<"NO"<<endl; 78 } 79 } 80 return 0; 81 }
留给自己做模板用5555
在给一个模板
1 bool spfa(int u) 2 { 3 vis[u] = true; 4 int i; 5 for(i = head[u]; i; i = e[i].next) 6 { 7 int v = e[i].to, w = e[i].w; 8 if(dis[v] > dis[u] + w) 9 { 10 dis[v] = dis[u] + w; 11 if(vis[v]) return false; 12 if(!spfa(v)) return false; 13 } 14 } 15 vis[u] = false; 16 return true; 17 }
纵使单枪匹马,也要勇闯天涯