• 【bzoj1486】[HNOI2009]最小圈 分数规划+Spfa


    题目描述

    样例输入

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

    样例输出

    3.66666667


    题解

    分数规划+Spfa判负环

    二分答案mid,并将所有边权减去mid,然后再判负环,若有负环则调整下界,否则调整上界,直至上下界基本重合。

    证明:显然 

    由于有(c+d)/(a+b+k)>(c+d)/(a+b)≥min(c/a,d/b),所以两个相交环形成的新环一定不是最优解,即答案一定是简单环。

    如果存在环使得边权和/点数<mid,那么就有边权和<点数*mid。

    又因为环中点数和边数相等,所以有边权和小于边数*mid,移项即得:存在负环。

    这个时候需要调整上界,进一步更新答案;否则不存在则调整下界。

    然后这道题的坑点:需要用dfs版Spfa判负环,据说bfs版会T,不明觉厉。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define eps 1e-9
    #define N 3010
    #define M 10010
    using namespace std;
    int n , m , head[N] , to[M] , next[M] , cnt , x[M] , y[M] , vis[N];
    double len[M] , dis[N] , z[M];
    void add(int x , int y , double z)
    {
        to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
    }
    bool dfs(int x)
    {
        int i;
        vis[x] = 1;
        for(i = head[x] ; i ; i = next[i])
        {
            if(dis[to[i]] > dis[x] + len[i])
            {
                dis[to[i]] = dis[x] + len[i];
                if(vis[to[i]]) return 1;
                if(dfs(to[i])) return 1;
            }
        }
        vis[x] = 0;
        return 0;
    }
    bool judge(double mid)
    {
        int i;
        memset(head , 0 , sizeof(head));
        memset(vis , 0 , sizeof(vis));
        memset(dis , 0 , sizeof(dis));
        cnt = 1;
        for(i = 1 ; i <= m ; i ++ ) add(x[i] , y[i] , z[i] - mid);
        for(i = 1 ; i <= n ; i ++ ) if(dfs(i)) return 1;
        return 0;
    }
    int main()
    {
        int i;
        double l = 100000000.0 , r = -100000000.0 , mid;
        scanf("%d%d" , &n , &m);
        for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%lf" , &x[i] , &y[i] , &z[i]) , l = min(l , z[i]) , r = max(r , z[i]);
        while(l <= r)
        {
            mid = (l + r) / 2;
            if(judge(mid)) r = mid - eps;
            else l = mid + eps;
        }
        printf("%.8lf
    " , (l + r) / 2);
        return 0;
    }

     

  • 相关阅读:
    Unity小地图Map
    DoTween扩展Transform
    Android开发笔记1.2
    Android开发笔记1.1.1
    Unity向量夹角
    使用vi
    MIPS 两个数的和(输入,计算,输出)
    python openpyxl 读取excel表操作
    javaI/O文件,读操作
    试用git遇见问题
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6855959.html
Copyright © 2020-2023  润新知