BZOJ1486 [HNOI2009]最小圈

今年的最后一篇了呢。。。好伤感的说,2014年还有1h就过去了

不不不回到正题,这道题嘛~看上去好神啊!

看到此题,我们可以联想到最优比例MST,于是就有了方法:

首先二分答案ans,判断ans是否可行,那如何判断呢?

每条边边权 - ans,之后在新的图中找负环即可。(可以用dfs版的spfa)

  1 /**************************************************************
  2     Problem: 1486
  3     User: rausen
  4     Language: C++
  5     Result: Accepted
  6     Time:284 ms
  7     Memory:1156 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <cstring>
 12
 13 using namespace std;
 14 typedef double lf;
 15 const int N = 3005;
 16 const int M = 10005;
 17 const int inf = 1e9;
 18 const lf eps = 1e-10;
 19
 20 inline int read() {
 21     int x = 0, sgn = 1;
 22     char ch = getchar();
 23     while (ch < ‘0‘ || ‘9‘ < ch) {
 24         if (ch == ‘-‘) sgn = -1;
 25         ch = getchar();
 26     }
 27     while (‘0‘ <= ch && ch <= ‘9‘) {
 28         x = x * 10 + ch - ‘0‘;
 29         ch = getchar();
 30     }
 31     return sgn * x;
 32 }
 33
 34 struct Edge {
 35     int x, y;
 36     lf v;
 37
 38     inline void Read() {
 39         x = read(), y = read();
 40         scanf("%lf", &v);
 41     }
 42 } E[M];
 43
 44 struct edge {
 45     int next, to;
 46     lf v;
 47     edge() {}
 48     edge(int _n, int _t, lf _v) : next(_n), to(_t), v(_v) {}
 49 } e[M];
 50
 51 int n, m;
 52 int first[N], tot;
 53 lf d[N];
 54 bool f, v[N];
 55
 56 inline void add_edge(int x, int y, lf v) {
 57     e[++tot] = edge(first[x], y, v);
 58     first[x] = tot;
 59 }
 60
 61 void spfa(int p) {
 62     int x, y;
 63     v[p] = 1;
 64     for (x = first[p]; x; x = e[x].next)
 65         if (d[p] + e[x].v < d[y = e[x].to]) {
 66             if (v[y]) {
 67                 f = 1;
 68                 break;
 69             } else
 70                 d[y] = d[p] + e[x].v, spfa(y);
 71         }
 72     v[p] = 0;
 73 }
 74
 75 void build_graph(lf x) {
 76     int i;
 77     tot = 0, memset(first, 0, sizeof(first));
 78     for (i = 1; i <= m; ++i)
 79         add_edge(E[i].x, E[i].y, E[i].v - x);
 80 }
 81
 82 bool check(lf x) {
 83     int i;
 84     build_graph(x);
 85     memset(v, 0, sizeof(v)), memset(d, 0, sizeof(d));
 86     for (i = 1, f = 0; i <= n; ++i) {
 87         spfa(i);
 88         if (f) return 1;
 89     }
 90     return 0;
 91 }
 92
 93 int main() {
 94     int i;
 95     scanf("%d%d", &n, &m);
 96     for (i = 1; i <= m; ++i)
 97         E[i].Read();
 98     lf l = -inf, r = inf, mid;
 99     while (l + eps < r) {
100         mid = (l + r) / 2;
101         if (check(mid)) r = mid; else l = mid;
102     }
103     printf("%.8lf\n", l);
104     return 0;
105 }

(p.s.  这就是神奇的叫"分数规划"的东西!!!)

时间: 2024-12-15 07:36:45

BZOJ1486 [HNOI2009]最小圈的相关文章

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 1486: [HNOI2009]最小圈 dfs求负环

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

[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

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千题计划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

【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 这个式

【bzoj1486】[HNOI2009]最小圈 分数规划+Spfa

题目描述 样例输入 4 5 1 2 5 2 3 5 3 1 5 2 4 3 4 1 3 样例输出 3.66666667 题解 分数规划+Spfa判负环 二分答案mid,并将所有边权减去mid,然后再判负环,若有负环则调整下界,否则调整上界,直至上下界基本重合. 证明:显然 由于有(c+d)/(a+b+k)>(c+d)/(a+b)≥min(c/a,d/b),所以两个相交环形成的新环一定不是最优解,即答案一定是简单环. 如果存在环使得边权和/点数<mid,那么就有边权和<点数*mid. 又因

【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 namespac

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