zoukankan      html  css  js  c++  java
  • [APIO2017]商旅

    洛咕

    题意:一张有向图(N(N<=100))个点(M(M<=10000))条边,有(K(K<=1000))种商品,每种商品在每个点有一个买入价格(b[i])和卖出价格(s[i]),也有可能某个点不支持某种商品的买入或卖出.同一时刻只能携带一种商品.求一个回路使得环路的盈利效率(指从环路中得到的收益除以花费的时间)最大,答案向下取整.

    分析:(N)(K)都很小,我们可以直接(floyd)预处理出每两个点之间的最短路(d[i][j],O(N^3)),以及每两个点之间的最大收益(w[i][j],O(N^2K)).

    又是这种比值最大,01分数规划的套路,二分mid,把每条边的边权设为(mid*d[u][i]-w[u][i]),然后判定负环就行了.

    本题很恶意,超级卡精度,反正我开了(long) (double)才过.

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
       int s=0,w=1;char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
       while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
       return s*w;
    }
    const int N=105;
    const int M=1005;
    long double eps=1e-10;
    int n,m,K;
    int b[N][M],s[N][M],w[N][N],d[N][N],visit[N];
    long double dis[N];
    inline bool dfs(int u,long double mid){
        visit[u]=1;
        for(int i=1;i<=n;i++)
            if(d[u][i]<1e9&&u!=i)
                if(dis[i]>dis[u]+mid*d[u][i]-w[u][i]){
                    dis[i]=dis[u]+mid*d[u][i]-w[u][i];
                    if(visit[i]||dfs(i,mid))return true;
                }
        visit[u]=0;
        return false;
    }
    inline bool check(long double mid){
        memset(dis,0,sizeof(dis));
        memset(visit,0,sizeof(visit));
        for(int i=1;i<=n;i++)if(dfs(i,mid))return true;
        return false;
    }
    int main(){
        n=read();m=read();K=read();
        for(int i=1;i<=n;i++)
    		for(int j=1;j<=K;j++)
    	    	b[i][j]=read(),s[i][j]=read();
        for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    	    	for(int k=1;k<=K;k++)
    		 		if(b[i][k]!=-1&&s[j][k]!=-1)
    		     		w[i][j]=max(w[i][j],s[j][k]-b[i][k]);
        for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    	    	d[i][j]=1e9;
        for(int i=1;i<=n;i++)d[i][i]=0;
        for(int i=1;i<=m;i++){
    		int a=read(),b=read(),c=read();
    		d[a][b]=c;
        }
        for(int k=1;k<=n;k++)
    		for(int i=1;i<=n;i++)
    	    	for(int j=1;j<=n;j++)
    				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
        long double l=0.0000,r=10000000000.0000;
        while(r-l>eps){
    		long double mid=(l+r)/2.0;
    		if(check(mid))l=mid;
    		else r=mid;
        }
        printf("%d
    ",(int)r);
        return 0;
    }
    
    
  • 相关阅读:
    linux内核主要模块图
    Linux0.11内核几种地址(逻辑地址、线性地址、物理地址)的含义
    Linux一个多线程的面试题
    进程的用户栈和内核栈
    Ubuntu 下安装LXR(linux源代码阅读工具)
    Linux多线程与同步
    实模式与保护模式
    Linux下的多线程编程
    寒假Day34:HTML表单+多媒体+框架
    寒假Day34:HDU1514Free Candies记忆化搜索
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10848369.html
Copyright © 2011-2022 走看看