码迷,mamicode.com
首页 > 其他好文 > 详细

[HNOI 2009]最小圈

时间:2017-10-09 16:44:51      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:i++   bsp   color   bool   else   font   add   style   scanf   

Description

对于一张有向图,要你求图中最小圈的平均值最小是多少,即若一个圈经过k个节点,那么一个圈的平均值为圈上k条边权的和除以k,现要求其中的最小值

Input

第一行2个正整数,分别为n和m

以下m行,每行3个数,表示边连接的信息,

Output

一行一个数,表示最小圈的值,保留8位小数。

Sample Input

4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3

Sample Output

3.66666667

HINT

若设边权为v,那么n≤3000,m≤10000,v≤50000

题解

最小化平均值($01$分数规划)。

使用二分求解。对于一个猜测的$mid$,只需判断是否存在平均值小于$mid$的回路。

如何判断?

假设存在一个包含$k$条边的回路,回路上各边权值为$w_1$ ,$w_2$ ,$...$,$w_k$ ,那么平均值小于$midv意味着:

$$w_1 +w_2 +...+w_k <k×mid$$

即:

$$(w_1 -mid)+(w_2 -mid)+...+(w_k -mid)<0$$

换句话说,只要把边$(a,b)$的权$w(a,b)$改成$w(a,b)-mid$,再判断新图中是否有负环即可。

存在负环,那么之前的不等式满足,即存在着更小的平均值,$r=mid$;不存在,$l=mid$。

 

 1 //It is made by Awson on 2017.10.9
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <cmath>
 7 #include <stack>
 8 #include <queue>
 9 #include <vector>
10 #include <string>
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
14 #include <iostream>
15 #include <algorithm>
16 #define LL long long
17 #define Min(a, b) ((a) < (b) ? (a) : (b))
18 #define Max(a, b) ((a) > (b) ? (a) : (b))
19 #define sqr(x) ((x)*(x))
20 using namespace std;
21 const double eps = 1e-9;
22 const int N = 3000;
23 const int M = 10000;
24 
25 int n, m, u, v, c;
26 bool vis[N+5];
27 double dist[N+5];
28 struct tt {
29   int to, next;
30   double cost;
31 }edge[M+5];
32 int path[N+5], top;
33 
34 void add(int u, int v, double c) {
35   edge[++top].to = v;
36   edge[top].next = path[u];
37   edge[top].cost = c;
38   path[u] = top;
39 }
40 bool dfs(int u, double dec) {
41   vis[u] = 1;
42   for (int i = path[u]; i; i = edge[i].next)
43     if (dist[edge[i].to] > dist[u]+edge[i].cost-dec) {
44       if (vis[edge[i].to]) return true;
45       dist[edge[i].to] = dist[u]+(double)edge[i].cost-dec;
46       if (dfs(edge[i].to, dec)) return true;
47     }
48   vis[u] = 0;
49   return false;
50 }
51 bool judge(double dec) {
52   for (int i = 1; i <= n; i++) {
53     memset(vis, 0, sizeof(vis));
54     memset(dist, 0, sizeof(dist));
55     if (dfs(i, dec)) return true;
56   }
57   return false;
58 }
59 void work() {
60   scanf("%d%d", &n, &m);
61   double L = 0, R = 0;
62   for (int i = 1; i <= m; i++) {
63     scanf("%d%d%d", &u, &v, &c);
64     add(u, v, c);
65     R = max(R, (double)c);
66   }
67   while (R-L >= eps) {
68     double mid = (L+R)/2.;
69     if (judge(mid)) R = mid;
70     else L =mid;
71   }
72   printf("%.8lf\n", (L+R)/2.);
73 }
74 int main() {
75   work();
76   return 0;
77 }

 

[HNOI 2009]最小圈

标签:i++   bsp   color   bool   else   font   add   style   scanf   

原文地址:http://www.cnblogs.com/NaVi-Awson/p/7641518.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!