• luogu P1768 天路 |01分数规划+负环


    题目描述

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

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

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

    输入格式

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

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

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

    输出格式

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

    若没有回路,输出-1。

    说明/提示

    对于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以内.


    01分数规划+负环

    ans>= (sum)vi/pi

    (sum) ans*p1-vi>=0

    把这个作为权值,然后找负环

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define db double
    using namespace std;
    const db eps=1e-2;
    const int N=7e3+10,M=2e4+10,inf=1<<29;
    int nxt[M],head[N],go[M],V[M],P[M],tot;
    inline void add(int u,int v,int o1,int o2){
    	nxt[++tot]=head[u];head[u]=tot;go[tot]=v;V[tot]=o1;P[tot]=o2;
    }
    db dis[N];
    bool vis[N];
    int used[N];
    int s;
    int n,m;
    inline bool spfa(db ans,int now){
      	vis[now]=true;
        for(int i=head[now];i;i=nxt[i]){
            int v=go[i];
            db x=ans*P[i]-V[i];
            if(dis[v]>dis[now]+x){
                if(vis[v])return 0;
                else{
                    dis[v]=dis[now]+x;
                    vis[now]=1;
                    if(!spfa(ans,v))return 0;
                }
            }
        }
        vis[now]=0;
        return 1;	
    }
    inline bool check(db x){
    	for(int i=1;i<=n;i++){
    		dis[i]=inf;
    		used[i]=0;
    		vis[i]=0;
    	}
    	return !spfa(x,s);
    }
    int main(){
    	cin>>n>>m;
    	db l=0,r=3000,ans=-1;
    	for(int i=1,u,v,o1,o2;i<=m;i++){
    		scanf("%d%d%d%d",&u,&v,&o1,&o2);
    		add(u,v,o1,o2);
    	}
    	s=n+1;
    	for(int i=1;i<=n;i++)add(s,i,0,0);
    	while(l+eps<r){
    		db mid=(l+r)/2;
    		if(check(mid)){
    			l=mid;
    			ans=mid;
    		}else{
    			r=mid;
    		}
    	}
    	if(ans==-1)printf("-1
    ");
    	else 
    	printf("%.1f
    ",ans);
    }
    
  • 相关阅读:
    HEOI2017游记
    uoj228:基础数据结构练习题
    bzoj1494【Noi2007】生成树计数
    bzoj1975【Sdoi2010】魔法猪学院
    bzoj2957:楼房重建
    uoj169:元旦老人与数列
    bzoj2178:圆的面积并
    一道好题
    Codeforces Round #440(Div.2)
    Codeforces Round #439 (Div. 2)
  • 原文地址:https://www.cnblogs.com/naruto-mzx/p/11625095.html
Copyright © 2020-2023  润新知