• [P1768]天路(分数规划+SPFA判负环)


    题目描述

    “那是一条神奇的天路诶~,把第一个神犇送上天堂~”,XDM先生唱着这首“亲切”的歌曲,一道猥琐题目的灵感在脑中出现了。

    和C_SUNSHINE大神商量后,这道猥琐的题目终于出现在本次试题上了,旨在难到一帮大脑不够灵活的OIer们(JOHNKRAM真的不是说你……)。

    言归正传,小X的梦中,他在西藏开了一家大型旅游公司,现在,他要为西藏的各个景点设计一组铁路线。但是,小X发现,来旅游的游客都很挑剔,他们乘 火车在各个景点间游览,景点的趣味当然是不用说啦,关键是路上。试想,若是乘火车一圈转悠,却发现回到了游玩过的某个景点,花了一大堆钱却在路上看不到好 的风景,那是有多么的恼火啊。

    所以,小X为所有的路径定义了两个值,Vi和Pi,分别表示火车线路的风景趣味度和乘坐一次的价格。现在小X想知道,乘客从任意一个景点开始坐火车 走过的一条回路上所有的V之和与P之和的比值的最大值。以便为顾客们推荐一条环绕旅游路线(路线不一定包含所有的景点,但是不可以存在重复的火车路线)。

    于是,小X梦醒之后找到了你……

    输入输出格式

    输入格式:

    第一行两个正整数N,M,表示有N个景点,M条火车路线,火车路线是单向的。

    以下M行,每行4个正整数,分别表示一条路线的起点,终点,V值和P值。

    注意,两个顶点间可能有多条轨道,但一次只能走其中的一条。

    输出格式:

    一个实数,表示一条回路上最大的比值,保留1位小数。

    若没有回路,输出-1。

    输入输出样例

    输入样例#1: 复制
    5 6
    1 2 1 1
    4 1 6 2
    5 4 8 1
    2 3 2 2
    5 2 4 1
    3 5 6 4
    输出样例#1: 复制
    2.3

    说明

    对于30%的数据,1≤N≤100,1≤M≤20;

    对于60%的数据,1≤N≤3,000,1≤M≤2,000;

    对于100%的数据,1≤N≤7,000,1≤M≤20,000,1≤Vi,Pi≤1,000.

    保证答案在200以内.

    分数规划裸题(主要是得想到这个算法),分数规划实际上就是移项之后的二分答案。

    二分之后SPFA判负环即可,注意要用DFS版的SPFA(这么重要的算法我以前竟然毫无所知)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 using namespace std;
     6 
     7 const int N=200010;
     8 struct P{ int to,nxt; double v1,v2; }e[N<<1];
     9 int n,m,u,v,len,h[N],vis[N],flag;
    10 double w1,w2,dis[N];
    11 
    12 void spfa(double now,int x){
    13     if (flag) return;
    14     vis[x]=1;
    15     for (int i=h[x],k; i; i=e[i].nxt)
    16         if (dis[k=e[i].to]>dis[x]+now*e[i].v2-e[i].v1){
    17             dis[k]=dis[x]+now*e[i].v2-e[i].v1;
    18             if (!vis[k]) spfa(now,k); else { flag=1; return; }
    19         }
    20     vis[x]=0;
    21 }
    22 
    23 bool check(double now){
    24     flag=0;
    25     memset(dis,0,sizeof(dis));
    26     memset(vis,0,sizeof(vis));
    27     rep(i,1,n){
    28         spfa(now,i);
    29         if (flag)break;
    30     }
    31     if (flag) return 1; return 0;
    32 }
    33 
    34 int main(){
    35     scanf("%d %d",&n,&m);
    36     rep(i,1,m){
    37         scanf("%d %d %lf %lf",&u,&v,&w1,&w2);
    38         e[++len].to=v; e[len].v1=w1; e[len].v2=w2; e[len].nxt=h[u]; h[u]=len;
    39     }
    40     double l=0,r=200.0,mid;
    41     while (l+0.01<r){
    42         mid=(l+r)/2;
    43         if (check(mid))l=mid; else r=mid;
    44     }
    45     if (l==0) printf("-1"); else printf("%.1lf",r);
    46     return 0;
    47 }
  • 相关阅读:
    按之字形打印二叉树 --剑指offer
    浅谈PHP+Access数据库的连接 注意要点
    Linux下统计代码行数
    获取服务器IP,客户端IP
    CURL访问举例
    廖雪峰博客
    Redis命令
    svn merge和branch 详解
    Linux Screen超简明教程
    MySQL 的Coalesce函数
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8462839.html
Copyright © 2020-2023  润新知