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;
    }
  • 相关阅读:
    POJ3253Fence Repair(优先队列或单调队列)
    POJ3630Phone List(字典树)
    HDU1896Stones(优先队列)
    POJ3468 A Simple Problem with Integers(线段树延时标记)
    HDU3535AreYouBusy(分组背包)
    C++ 学习涨姿势汇总
    [C++] std::vector 使用
    Cocos2dx-3.2 引擎学习(四)之CCScheduler
    Cocos2dx-3.2 引擎学习(三)之AssetsManager
    Cocos2dx-3.2 引擎学习(二)之Director
  • 原文地址:https://www.cnblogs.com/lalawu/p/3574990.html
Copyright © 2011-2022 走看看