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:array[0..maxm]of longint;
8 w:array[0..maxm]of double;
9 n,m:longint;
10
11 procedure init;
12 var
13 i,x:longint;
14 begin
15 read(n,m);
16 for i:=1 to m do
17 begin
18 read(x);
19 read(last[i],w[i]);
20 next[i]:=first[x];
21 first[x]:=i;
22 end;
23 end;
24
25 var
26 flag,vis:array[0..maxn]of longint;
27 dis:array[0..maxn]of double;
28 time,time2:longint;
29 ans:double;
30
31 function dfs(x:longint;f:double):boolean;
32 var
33 i:longint;
34 begin
35 flag[x]:=time;
36 vis[x]:=time2;
37 dis[x]:=f;
38 i:=first[x];
39 while i<>0 do
40 begin
41 if f+w[i]-ans<=0 then
42 begin
43 if vis[last[i]]=time2 then
44 if dis[last[i]]>=f+w[i]-ans then exit(true);
45 if vis[last[i]]<>time2 then
46 if dfs(last[i],f+w[i]-ans) then exit(true);
47 end;
48 i:=next[i];
49 end;
50 vis[x]:=time2-1;
51 exit(false);
52 end;
53
54 procedure work;
55 var
56 i:longint;
57 l,r:double;
58 f:boolean;
59 begin
60 l:=-10000001;
61 r:=-l;
62 while r-l>1e-9 do
63 begin
64 ans:=(l+r)/2;
65 inc(time);
66 f:=false;
67 for i:=1 to n do
68 if flag[i]<>time then
69 begin
70 inc(time2);
71 if dfs(i,0) then
72 begin
73 f:=true;
74 break;
75 end;
76 end;
77 if f then r:=ans
78 else l:=ans;
79 end;
80 writeln(ans:0:8);
81 end;
82
83 begin
84 init;
85 work;
86 end.

1486: [HNOI2009]最小圈 - BZOJ,码迷,mamicode.com

时间: 2024-09-30 00:28:54

1486: [HNOI2009]最小圈 - BZOJ的相关文章

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][HNOI2009]最小圈(二分答案+dfs写的spfa判负环)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1486 分析:容易想到先二分答案x,然后把所有边的权值-x,那么如果图中存在权值和为0的环那就最好不过了,说明我们找到了这个环,但如果存在负环,则说明我们的x还可以更小,如果不存在负环,则说明我们的x大了.所以接下来的问题是如何判断负环了.可以用spfa,但bfs做的会TLE,因为每个点的松弛不具有连续性,如果用dfs写的话则效率会大大提高.2009集训队论文中有涉及.

bzoj 1486: [HNOI2009]最小圈

二分答案再判负环 #include<cstdio> #include<algorithm> using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read

【BZOJ】1486 [HNOI2009]最小圈

[算法]二分+spfa [题解]据说这个叫分数规划? 0-1分数规划 二分答案a,则对于任意的环有w/k≤a即w-ak≤0,若满足条件则a变小,否则a变大. 因为w=w1+w2+...+wk,所以变形为(w1-a)+(w2-a)+...+(wk-a)≤0.于是问题转化为在图中找负环. 不过由于spfa限制,"="没办法并入"<",但是由于精度足够,最后也就是1.00000000001≈1.00000000. 使用DFS的spfa:可以在发现更新到之前更新过的节

BZOJ 1486 HNOI2009 最小圈 二分答案+DFS

题目大意:裸的最优比例环 直接二分答案+SPFA 这样会T 因为数据卡SPFA SPFA在负环非常小的时候会退化成Bellman-Ford 时间复杂度是O(nm) (好像是O(n*m^2)?我忘了)的 换一种方法 枚举每个点 从每个点开始DFS 只沿着能将指向的点dis减小的边搜索 搜到栈中的点就返回true 期望复杂度O(n^2) 最坏复杂度O(2^n) 这种东西能过我也是醉了- - #include <cstdio> #include <cstring> #include &l

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

[HNOI2009]最小圈

hnoi2009最小圈 Description #include<iostream> #include<cstdio> #include<cstring> #define maxn 3005 #define maxe 10005 using namespace std; struct Edge { int v; double w; int next; }e[maxe]; int head[maxn],cnts=0,n,m; double eps=1e-9,dis[max

【bzoj1486】 HNOI2009—最小圈

http://www.lydsy.com/JudgeOnline/problem.php?id=1486 (题目链接) 题意:给出一张有向图,规定一个数值u表示图中一个环的权值/环中节点个数.求最小的u. Solution  尼玛今天考试题,不知道是考二分的话这真的做不出..  二分一个答案ans,这个答案可行当且仅当ans>=∑w/cnt,cnt表示环中节点个数.移项,ans*cnt-∑w>=0,而w的个数又正好等于cnt,所以最后的式子变成了: ∑i=0n(ans−w)>=0 这个式