zoukankan      html  css  js  c++  java
  • bzoj1486 [HNOI2009]最小圈

    1486: [HNOI2009]最小圈

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 2723  Solved: 1310
    [Submit][Status][Discuss]

    分析:分数规划.

       其实就是最小化,令其 = ans,那么化简一下就是:.如果ans过大,则左边会小于0,如果过小,则左边会大于0.事实上这就是一个二分的过程.将ans看作平均权值.代到式子中,那么式子表示的意义就是将所有边权减掉ans后是否存在负环.

    这里用dfs版的spfa特判一下就好了.

       我的这份代码还有许多可以优化的地方.在实数范围内二分不仅可以比较精度,还可以设定一个循环次数,通常后者更好一些.

    每次选取一个点做spfa并不需要清空vis和d数组.事实上不优化这两个地方也能过.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const double eps = 1e-9,inf = 1000000000000000000.0;
    const int maxn = 10010;
    
    struct node
    {
        int x,y;
        double len;
    } e[maxn];
    
    int n,m,head[maxn],to[maxn],nextt[maxn],tot = 1,vis[maxn];
    double ans,w[maxn],d[maxn];
    bool flag = false;
    
    void add(int x,int y,double z)
    {
        w[tot] = z;
        to[tot] = y;
        nextt[tot] = head[x];
        head[x] = tot++;
    }
    
    void spfa(int u)
    {
        vis[u] = 1;
        for (int i = head[u]; i; i = nextt[i])
        {
            int v = to[i];
            if (d[v] > d[u] + w[i])
            {
                if (vis[v])
                {
                    flag = true;
                    break;
                }
                else
                {
                    d[v] = d[u] + w[i];
                    spfa(v);
                }
            }
        }
        vis[u] = 0;
    }
    
    bool check(double x)
    {
        memset(head,0,sizeof(head));
        flag = false;;
        tot = 1;
        for (int i = 1; i <= m; i++)
            add(e[i].x,e[i].y,e[i].len - x);
        for (int i = 1; i <= n; i++)
        {
            memset(vis,0,sizeof(vis));
            memset(d,127/3,sizeof(d));
            d[i] = 0;
            spfa(i);
            if (flag)
                return true;
        }
        return false;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i = 1; i <= m; i++)
            scanf("%d%d%lf",&e[i].x,&e[i].y,&e[i].len);
        double l = -10000000,r = 10000000;
        while (r - l > eps)
        {
            double mid = (l + r) / 2;
            if (check(mid))
            {
                ans = mid;
                r = mid;
            }
            else
                l = mid;
        }
        printf("%.8lf
    ",ans);
    
        return 0;
    }
  • 相关阅读:
    【BZOJ 4151 The Cave】
    【POJ 3080 Blue Jeans】
    【ZBH选讲·树变环】
    【ZBH选讲·拍照】
    【ZBH选讲·模数和】
    【CF Edu 28 C. Four Segments】
    【CF Edu 28 A. Curriculum Vitae】
    【CF Edu 28 B. Math Show】
    【CF Round 439 E. The Untended Antiquity】
    【CF Round 439 C. The Intriguing Obsession】
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8448125.html
Copyright © 2011-2022 走看看