【dfs判负环】BZOJ1489: [HNOI2009]最小圈

Description

找出一个平均边权最小的圈。

 

Solution

经典问题,二分答案判断有无负环。

但数据范围大,普通spfa会超时,于是用dfs判负环(快多了)。

思路是dis设为0,枚举每个点u,如果d(u)+w<d(v)就搜v,如果搜到的节点曾搜到过说明找到了负环。

为什么是对的呢?对于一个负环,一定可以找到一个节点从这里开始走一直累加权值,权值一直为负。

 

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=3e5+5,M=1e4+5;
 6 
 7 int head[M],e[M],nxt[M],k;
 8 double w[M];
 9 int adde(int u,int v,double g){
10     e[++k]=v;w[k]=g;nxt[k]=head[u];head[u]=k;
11 }
12 int n,m;
13 
14 double d[N];
15 int vis[N],flag;
16 
17 int spfa(int u){
18     vis[u]=1;
19     for(int i=head[u];i;i=nxt[i]){
20         int v=e[i];
21         if(d[u]+w[i]<d[v]){
22             if(vis[v]){flag=1;break;}
23             d[v]=d[u]+w[i];
24             spfa(v);
25         }
26     }
27     vis[u]=0;
28 }
29 
30 int jud(double mid){
31     for(int i=1;i<=k;i++) w[i]-=mid;
32     memset(d,0,sizeof(d));
33     memset(vis,0,sizeof(vis));
34     flag=0;
35     int ret=0;
36     for(int i=1;i<=n;i++){
37         spfa(i);
38         if(flag){ret=1;break;}
39     }
40     for(int i=1;i<=k;i++) w[i]+=mid;
41     return ret;
42 }
43 
44 int main(){
45     scanf("%d%d",&n,&m);
46     int u,v; double g;
47     for(int i=1;i<=m;i++){
48         scanf("%d%d%lf",&u,&v,&g);
49         adde(u,v,g);
50     }
51     
52     double l=-1e7,r=1e7;
53     while(r-l>1e-10){
54         double mid=(l+r)/2;
55         if(jud(mid)) r=mid;
56         else l=mid;
57     }
58     printf("%.8lf",l);
59     return 0;
60 }

 

posted @ 2015-06-11 00:35  CyanNode  阅读(696)  评论(0编辑  收藏  举报