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

Description

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

Solution

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

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

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

感慨一下dfs真是神奇。

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 }
时间: 2024-12-09 21:56:29

【dfs判负环】BZOJ1489: [HNOI2009]最小圈的相关文章

【BZOJ1486】【HNOI2009】最小圈 分数规划 dfs判负环。

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46348771"); } 题解: 分数规划Qwq. 然而它卡判点入n次的那种spfa推断负环. 于是有了一种黑科技: 我们从枚举点 i 開始 dfs .然后扫到点 j 时.保持 i~j 这一条链上的点被标记,然后强行推

SPFA的BFS与DFS实现及判负环问题

经过笔者的多次实践(失败),在此温馨提示:用SPFA判负环时一定要特别小心! 首先SPFA有BFS和DFS两种实现方式,两者的判负环方式也是不同的. DFS是如果找到一个节点已经在递归栈中则表示出现负环(即你层层向下搜索后又回到了起点,很明显有负环),BFS是用一个数组记录每一个节点的入队次数,如果某个节点入队次数超过n(节点数)次则表示出现负环(根据SPFA的原理,每一个点最多被扩展n次就会出结果的,如果超过了n次算法还没结束,自然是有负环).看起来是简单,但有以下注意事项: 如果只是判负环,

bzoj 1486: [HNOI2009]最小圈 dfs求负环

1486: [HNOI2009]最小圈 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1022  Solved: 487[Submit][Status] Description 最开始写floyd求负环结果TLE了,改成dfs后速度变成原来的100+倍.反正还是比较神奇.

BZOJ 1486: [HNOI2009]最小圈( 二分答案 + dfs判负圈 )

二分答案m, 然后全部边权减掉m, 假如存在负圈, 那么说明有平均值更小的圈存在. 负圈用dfs判断. --------------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; ++i) #define clr(x, c) memset(x, c, sizeof(x)) #define

BZOJ 1486 最小圈(二分+判负环)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1486 题意:给出一个有向图,边有权值.找到一个环,使得环上边的权值之和除以环上边的个数最小. 思路:二分答案x,每条边权值减去x,之后 找负环.从每个顶点开始DFS,记录到达某个顶点的距离,设当前DFS的顶点为u,距离dis[u].下一个顶点v, 权值w,则dis[u]+w<=0时才DFS(v).另外,若v是已经遍历过的,且dis[u]+w-dis[v](这个dis[v]是之前遍历时

1486: [HNOI2009]最小圈 - BZOJ

在机房的小伙伴提醒是二分之后,我想到了是判负环,所以我用spfa,而且我保持dis都是小于等于0,本以为这样就能过了,可是还是有一个点达到了3.8s左右(其他都是0.0几秒) 所以还是写了dfs版本,还是一样每次都保持dis小于等于0,当发现有一个点在栈中,你又可以更新他的dis,那么就有负环了 1 const 2 maxn=3010; 3 maxm=10010; 4 inf=99999; 5 var 6 first:array[0..maxn]of longint; 7 next,last:a

bzoj千题计划227:bzo1486: [HNOI2009]最小圈j

http://www.lydsy.com/JudgeOnline/problem.php?id=1486 二分答案 dfs版spfa判负环 #include<queue> #include<cstdio> #include<cstring> #include<iostream> #define N 3001 #define M 10001 using namespace std; int n; int tot,front[N],nxt[M],to[M]; d

洛谷P3385 【模板】负环 DFS-SPFA 判负环 图论

洛谷P3385 [模板]负环 图论 今天get了 一个 DFS-SPFA 判负环的方法 一般的 BFS-SPFA 判负环 一般就是 不停地做,如果某点第 n+1次加入队列中,那么说明这个图存在负环然而我并不会证明,期望复杂度是 O(kM) k 大约是在 2 左右 但是其实对于一些极限数据,最坏可以把他卡到 O( NM) 额,这就直接炸飞了是不是,而且据说,一些数据比较强的题目,总会想到卡一卡SPFA的, 然后我们换一种思路 因为题目中一定存在一种 负环对吧,所以说假如你某段路径权值和为自然数的时

uva11090 Going in Cycle!! --- 二分+spfa判负环

给一个带权有向图,求其中是否存在环,若存在,输出环上边权的平均值最小的那个的平均值. 点的范围就50,感觉可以很暴力..但显然超时了 感觉方法好巧妙,二分平均值,将所有边权减去二分的那个值,然后spfa判断是否有负环 若有负环,则图中存在的所有环的边权平均值一定比枚举值大 反之则小,要是无论枚举值多大都没有负环,说明图中没有环. #include <iostream> #include <cstring> #include <string> #include <c