zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    java集合
    [编写高质量代码:改善java程序的151个建议]建议57 推荐在复杂字符串操作中使用正则表达式
    [编写高质量代码:改善java程序的151个建议]建议53 注意方法中传递的参数要求
    判断某一时间范围的方法
    c#读写xml文件
    冒泡排序
    C#使用正则表达式检测数字 char 和韩文
    三角形面积公式
    unity 绘制三角形
    中缀转后缀表达式
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6428687.html
Copyright © 2011-2022 走看看