zoukankan      html  css  js  c++  java
  • [WIKIOI1183]泥泞的道路[二分答案+SPFA]

    http://www.wikioi.com/problem/1183/

    分析一下其实很简单的,转换成图论就可以做了。

    这个题目是满足二分答案的性质的,因为对于一个答案a,如果a可以,那么比a小的必然也可以。

    所以我们先用二分答案去枚举

    但是这个二分答案需要注意精度问题,具体是什么呢?

    一般二分答案是while(l <= r) if(check(mid)) l = mid + 1; else r = mid - 1;

    这样的,愚蠢的我一开始就这样写了,然后精度错误balalalala的

    cheeck怎么写呢,有一个p[i]是路程,对于答案ans

    满足 你走的路程 / 耗费的时间 = ans

    然后就可以根据这个等式去构图,以p[i][j] - t[i][j] * ans为边权,然后求最长路,如果有环这个ans肯定合法,如果没环但是dist[n] >=0 也合法

    接下来贴代码

    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #define mod 9999973
    #define inf 10000000
    #define N 105
    using namespace std;
    int n , p[N][N] , t[N][N] , num[N];
    bool inq[N];
    double map[N][N] , d[N] , sum , sum1;
    queue <int> q;
    bool check(double ans)
    {
        //构图
        memset(map , 0 , sizeof(map));
        memset(inq , 0 , sizeof(inq));
        while(!q.empty()) q.pop();
        for(int i = 1 ; i <= n ; ++i) d[i] = (double)-1e8 , num[i] = 0;
        for(int i = 1 ; i <= n ; ++i)
            for(int j = 1 ; j <= n ; ++j)
            {
                if(i == j) continue;
                map[i][j] = (double)p[i][j] - (double)t[i][j] * ans;
            }
        q.push(1) , inq[1] = 1;
        d[1] = 0 , ++num[1];
        while(!q.empty())
        {
            int po = q.front(); q.pop();
            inq[po] = 0;
            if(num[po] > n)
            {
                d[n] = 1e8; break; 
            }
            for(int i = 1 ; i <= n ; ++i)
            {
                if(po == i) continue;
                if(d[i] < d[po] + map[po][i])
                {
                    d[i] = d[po] + map[po][i];
                    if(!inq[i]) q.push(i) , inq[i] = 1 , ++num[i];
                }
            }
        }
        if(d[n] >= 0) return 1;
        return 0;
    }
    void work()
    {
        scanf("%d", &n);
        double l = 0 , r = 0 , mid;
        for(int i = 1 ; i <= n ; ++i) for(int j = 1 ; j <= n ; ++j) scanf("%d", &p[i][j]) , sum += p[i][j];
        for(int i = 1 ; i <= n ; ++i) for(int j = 1 ; j <= n ; ++j)
        {
            scanf("%d", &t[i][j]) , sum1 += t[i][j];
            if(p[i][j]) r = max(r , (double)p[i][j] / (double)t[i][j]);
        }
        l = sum / sum1;
        mid = (l + r) / 2;
        while(1)
        {
            if(r - l <= 0.00001) {printf("%.3lf" , mid); break;}
            if(check(mid)) l = mid; else r = mid;
            mid = (l + r) / 2;
        } 
    }
    int main()
    {
        work();
        return 0;
    }
  • 相关阅读:
    [FAQ] GitHub 开启二次验证之后,如何通过 https clone 项目 ?
    [FAQ] GoLand 需要手动开启代码补全吗 ?
    [FAQ] 夏玉米 按规则查询域名靠谱吗 ?
    [FAQ] Error: com.mysql.jdbc.Driver not loaded. :jdbc_driver_library
    [php-src] Php内核的有趣高频宏
    [php-src] Php扩展开发的琐碎注意点、细节
    [ELK] Docker 运行 Elastic Stack 支持 TLS 的两种简单方式
    [Contract] Solidity 生成随机数方案
    [MySQL] 导入数据库和表的两种方式
    [ELK] 生产环境中 Elasticsearch 的重要配置项
  • 原文地址:https://www.cnblogs.com/lalawu/p/3574990.html
Copyright © 2011-2022 走看看