APIO2017

Posted on 2018-02-11 11:14  Amphetamine  阅读(262)  评论(0编辑  收藏  举报

商旅

在广阔的澳大利亚内陆地区长途跋涉后,你孤身一人带着一个背包来到了科巴。你被这个城市发达而美丽的市场所
深深吸引,决定定居于此,做一个商人。科巴有个集市,集市用从1到N的整数编号,集市之间通过M条单向道路连
接,通过每条道路都需要消耗一定的时间。在科巴的集市上,有K种不同的商品,商品用从1到K的整数编号。每个
集市对每种商品都有自己的定价,买入和卖出商品的价格可以是不同的。并非每个集市都可以买卖所有的商品:一
个集市可能只提供部分商品的双向交易服务;对于一种商品,一个集市也可能只收购而不卖出该商品或只卖出而不
收购该商品。如果一个集市收购一种商品,它收购这种商品的数量是不限的,同样,一个集市如果卖出一种商品,
则它卖出这种商品的数量也是不限的。为了更快地获得收益,你决定寻找一条盈利效率最高的环路。环路是指带着
空的背包从一个集市出发,沿着道路前进,经过若干个市场并最终回到出发点。在环路中,允许多次经过同一个集
市或同一条道路。在经过集市时,你可以购买或者卖出商品,一旦你购买了一个商品,你需要把它装在背包里带走
。由于你的背包非常小,任何时候你最多只能持有一个商品。在购买一个商品时,你不需要考虑你是否有足够的金
钱,但在卖出时,需要注意只能卖出你拥有的商品。从环路中得到的收益为在环路中卖出商品得到的金钱减去购买
商品花费的金钱,而一条环路上消耗的时间则是依次通过环路上所有道路所需要花费的时间的总和。环路的盈利效
率是指从环路中得到的收益除以花费的时间。需要注意的是,一条没有任何交易的环路的盈利效率为0。你需要求
出所有消耗时间为正数的环路中,盈利效率最高的环路的盈利效率。答案向下取整保留到整数。如果没有任何一条
环路可以盈利,则输出0。
 
 
 
 
 

Input

第一行包含3个正整数N,M和K,分别表示集市数量、道路数量和商品种类数量。
接下来的N行,第行中包含2K个整数描述一个集市Bi,1 Si,1 Bi,2 Si,2...Bik Si,k。
对于任意的1<=j<=k,整数和分别表示在编号为的集市上购买、卖出编号为的商品时的交易价格。
如果一个交易价格为-1,则表示这个商品在这个集市上不能进行这种交易。
接下来M行,第行包含3个整数Vp,Wp和Tp,表示存在一条从编号为Vp的市场出发前往编号为Wp的市场的路径花费Tp分钟。
1<=N<=100,1<=M<=9900
如果在编号为的集市i中,编号为j的商品既可以购买又可以卖出则0<Si,j<=Bi,j<=10^9
对于编号为P(1<=P<=M)的道路,保证Vp<>Wp且1<=Tp<=10^7
不存在满足1<=P<Q<=M的P,Q,使得(Vp,Wp)=(Vq,Wq) 。
 

Output

输出包含一个整数,表示盈利效率最高的环路盈利效率,答案向下取整保留到整数。如果没
有任何一条环路可以盈利,则输出0。
 

Sample Input

4 5 2
10 9 5 2
6 4 20 15
9 7 10 9
-1 -1 16 11
1 2 3
2 3 3
1 4 1
4 3 1
3 1 1

Sample Output

2
 
看起来像一个分数规划,实际上就是分数规划。。。。。
一开始百思不得解,但是数据分范围真的良心啊有木有。
 
100???n3???n3log
两点之间最短路可以floyd
首先二分,然后判断。
w[i][j]表示从i走到j能得到的最大盈利
calc[i][j]=w[i][j]-dis[i][j]*k
显然calc也可以floyd
枚举所有calc[i][i]如果有大于0的则代表成立。
 
#include<bits/stdc++.h>
using namespace std;
#define N 110
#define ll long long
#define inf 10000000000ll
#ifdef ONLINE_JUDGE
char *TT,*mo,but[(1<<15)+2];
#define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin)),TT==mo)?0:*TT++)
#endif
inline ll read(){
    ll x=0;int c=0,f=1;
    for(;c<'0'||c>'9';c=getchar())f=c!='-';
    for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
    return f?x:-x;
}
ll dis[N][N],calc[N][N],p[N][N];
ll a[N][N*10],b[N][N*10];
int n,m,K;
inline bool check(ll x) {
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++) {
            if (dis[i][j]==inf)calc[i][j]=-inf;
            else {
                calc[i][j]=p[i][j]-dis[i][j]*x;
                calc[i][j]=max(-inf,calc[i][j]);
            }
        }
        calc[i][i]=-inf;
    }
    ll res=-inf;
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                calc[i][j]=max(calc[i][j],calc[i][k]+calc[k][j]);
                res=max(res,calc[i][i]);
                if(res>=0){
                    return 1;
                }
                calc[i][j]=min(calc[i][j],inf);
            }
        }
    }
    return 0;
}
int main(){
    n=read(),m=read(),K=read();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=K;j++){
            a[i][j]=read(),b[i][j]=read();
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)dis[i][j]=inf;
    }
    for(int i=1;i<=n;i++)dis[i][i]=0;
    int u,v,c;
    for(int i=1;i<=m;i++){
        u=read(),v=read(),c=read();
        dis[u][v]=min(dis[u][v],(ll)c);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
                dis[j][k]=min(dis[j][k],dis[j][i]+dis[i][k]);
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=K;k++){
                if(b[j][k]==-1||a[i][k]==-1)continue;
                p[i][j]=max(p[i][j],b[j][k]-a[i][k]);
            }
        }
    }
    ll l=1,r=1000000000;
    while (l < r-1) {
        ll mid=l+r>>1;
        if(check(mid))l=mid;
        else r=mid-1;
    }
    if(check(r))cout<<r<<endl;
    else cout<<l<<endl;
    return 0;
}
View Code