POJ 3621:Sightseeing Cows(最优比率环)

http://poj.org/problem?id=3621

题意:有n个点m条有向边,每个点有一个点权val[i],边有边权w(i, j)。找一个环使得Σ(val) / Σ(w)最大,并输出。

思路:和之前的最优比率生成树类似,还是构造成这样的式子:F(L) = Σ(val[i] * x[i]) - Σ(w[i] * x[i] * L) = Σ(d[i]) * x[i] (d[i] = val[i] - w[i] * L),要使得L越大越好。

那么当L越大的时候,F(L)就越小,如果F(L)大于等于0的话,说明是可以改进的,于是要找最大的d[i],使得结果更优。这样就是求最长路并判正环。但是并不好处理。

那么反过来,F(L) = Σ(-d[i] * x[i]),就是要求得最短路并判负环,这样就可以直接套SPFA了。如果有负环的话,说明可以得到更优的结果。

还有起点是不固定的,于是一开始先把所有的点入队,然后再去求。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 #include <queue>
 6 using namespace std;
 7 #define N 10010
 8 #define INF 0x3f3f3f3f
 9 const double eps = 1e-9;
10 struct Edge {
11     int v, w, nxt;
12 } edge[N];
13 int n, m, val[N], vis[N], tid[N], head[N], tot;
14 double dis[N];
15 
16 void Add(int u, int v, int w) { edge[tot] = (Edge) {v, w, head[u]}; head[u] = tot++; }
17 
18 bool SPFA(double k) {
19     queue<int> que;
20     memset(tid, 0, sizeof(tid));
21     for(int i = 1; i <= n; i++) que.push(i), vis[i] = 1, dis[i] = 0, tid[i] = 1;
22     while(!que.empty()) {
23         int u = que.front(); que.pop();
24         tid[u]++; vis[u] = 0;
25         if(tid[u] > n) return false;
26         for(int i = head[u]; ~i; i = edge[i].nxt) {
27             int v = edge[i].v;
28             double d = (double)val[v] - k * edge[i].w;
29             if(dis[v] > dis[u] - d) {
30                 dis[v] = dis[u] - d;
31                 if(!vis[v]) vis[v] = 1, que.push(v);
32             }
33         }
34     }
35     return true;
36 }
37 
38 double solve() {
39     double l = 0, r = INF;
40     while(fabs(r - l) > eps) {
41         double mid = (l + r) / 2;
42         if(SPFA(mid)) r = mid;
43         else l = mid;
44     }
45     return l;
46 }
47 
48 int main() {
49     while(~scanf("%d%d", &n, &m)) {
50         tot = 0; memset(head, -1, sizeof(head));
51         for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
52         for(int i = 0; i < m; i++) {
53             int u, v, w;
54             scanf("%d%d%d", &u, &v, &w);
55             Add(u, v, w);
56         }
57         printf("%.2f
", solve());
58     }
59     return 0;
60 }
原文地址:https://www.cnblogs.com/fightfordream/p/6428687.html