首页 > 代码库 > BZOJ1486 [HNOI2009]最小圈

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 }
View Code

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

BZOJ1486 [HNOI2009]最小圈