• codevs1183 泥泞的道路


    题目描述 Description
    CS有n个小区,并且任意小区之间都有两条单向道路(a到b,b到a)相连。因为最近下了很多暴雨,很多道路都被淹了,不同的道路泥泞程度不同。小A经过对近期天气和地形的科学分析,绘出了每条道路能顺利通过的时间以及这条路的长度。

    现在小A在小区1,他希望能够很顺利地到达目的地小区n,请帮助小明找出一条从小区1出发到达小区n的所有路线中(总路程/总时间)最大的路线。请你告诉他这个值。

    输入描述 Input Description
    第一行包含一个整数n,为小区数。

    接下来n*n的矩阵P,其中第i行第j个数表示从小区i到小区j的道路长度为Pi,j。第i行第i个数的元素为0,其余保证为正整数。

    接下来n*n的矩阵T,第i行第j个数表示从小区i到小区j需要的时间Ti,j。第i行第i个数的元素为0,其余保证为正整数。

    输出描述 Output Description
    写入一个实数S,为小区1到达n的最大答案,S精确到小数点后3位。

    样例输入 Sample Input
    3
    0 8 7
    9 0 10
    5 7 0
    0 7 6
    6 0 6
    6 2 0

    样例输出 Sample Output
    2.125

    数据范围及提示 Data Size & Hint
    【数据说明】
    30%的数据,n<=20
    100%的数据,n<=100,p,t<=10000

    分析:
    一开始以为是一道dp
    想起了这道题

    但是这个t的范围好大
    枚举不就jj了吗
    那怎么办呢

    tag上说是二分

    第一反应,二分时间
    看在mid的时间内能够走到哪里
    能到达n的话,就统计一下答案,r=mid
    不能的话l=mid

    但是我们不能保证这样就具有单调性啊(二分的要求就是答案具有单调性)
    况且二分t的范围不也是很大吗,zz

    那我们还能二分什么呢
    只能二分最大值了

    那问题就在如何判定可行性上
    (s1+s2+s3)/(t1+t2+t3)=ans
    难道我们要走一步看一步嘛
    太不现实了

    想到这里,就体现了oi们必须具备的一个重要思想

    画柿子!

    (s1+s2+s3)=ans*(t1+t2+t3)
    s1+s2+s3=ans*t1+ans*r2+ans*t3
    (s1-ans*t1)+(s2-ans*t2)+(s3-ans*t3)=0

    这样一看,ans就和我们经过的每一条边都有直接关系了
    我们可以把边权变成s-ans*t
    每次跑一个最长路
    看一看答案是不是>0
    是则l=mid
    否则r=mid

    tip

    每一种元素都要尝试一下,
    熟练掌握画柿子的本领

    等我第一遍写完之后,怎么也跑不出来答案,
    后来看前辈在spfa的时候有一个特判

    ti[way[i].y]++;
    if (ti[way[i].y]>=n) return 1;

    这个是判断环的
    ti表示每个元素的入队次数,如果一个点的入队次数大于等于n,那么ta一定在一个环上,如果存在正环,那么一定符合条件

    这里写代码片
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    
    using namespace std;
    
    const int N=102;
    const double eps=1e-4;
    const double INF=1e7;
    int mp[N][N],t[N][N];
    int n,sum=0;
    struct node{
        int x,y,nxt;
        double v;
    };
    node way[2*N*N];
    int st[N],tot;
    double dis[N];
    int q[N*N],tou,wei,ti[N];
    bool p[N];
    
    int dcmp(double x)
    {
        if (x>=eps) return 1;
        else return 0;
    }
    
    void add(int u,int w,double z)
    {
        tot++;
        way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
    }
    
    int spfa()
    {
        for (int i=1;i<=n;i++) p[i]=1,dis[i]=-INF;
        memset(ti,0,sizeof(ti));
        tou=wei=0;
        q[++wei]=1;
        dis[1]=0.0;p[1]=0;ti[1]=1;
        do
        {
            int r=q[++tou];
            for (int i=st[r];i;i=way[i].nxt)
            {
                if (way[i].v+dis[r]>dis[way[i].y])
                {
                    dis[way[i].y]=way[i].v+dis[r];
                    if (p[way[i].y])
                    {
                        p[way[i].y]=0;
                        q[++wei]=way[i].y;
                        ti[way[i].y]++;
                        if (ti[way[i].y]>=n) return 1;
                    }
                }
            }
            p[r]=1;
        }
        while (tou<wei);
        if (dis[n]>=0) return 1;
        else return 0;
    }
    
    int pd(double mid)
    {
        memset(st,0,sizeof(st)); 
        tot=0;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
            if (i!=j)
            {
                double x=((double)mp[i][j]-mid*(double)t[i][j]);
                add(i,j,x);
            }
        return spfa();
    }
    
    void erfen()
    {
        double ans=0;
        double l=0,r=(double)sum;
        while (dcmp(r-l))
        {
            double mid=(l+r)/2;
            if (pd(mid))
               ans=max(ans,mid),l=mid;
            else r=mid;
        }
        printf("%0.3lf",ans);
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                scanf("%d",&mp[i][j]),sum+=mp[i][j];
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                scanf("%d",&t[i][j]);
        erfen();
        return 0;
    }
  • 相关阅读:
    菜根谭#245
    菜根谭#244
    菜根谭#243
    菜根谭#242
    菜根谭#241
    菜根谭#240
    菜根谭#239
    菜根谭#238
    菜根谭#237
    [转载]Linux 内核list_head 学习(一)
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673188.html
Copyright © 2020-2023  润新知