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

    APIO2017 商旅

    题目传送门

    题意

    给出一个(N)个点(M)条边的有向图,你可以在每个点对于一些特定的商品进行买卖。一共有(K)种商品,在每一个点,每一种商品都有一个买入值(B_i)和一个卖出值(S_i)。每一条边有一个边权(T_i),表示经过这条边的时间。定义一条环路的盈利效率为在这条环路上能够获得的利益最大值除以在这条环路上花费的时间,求盈利效率最大的一条环路。
    ((1 leq N leq 100 , 1 leq M leq 9900 , 1 leq K leq 1000 , 1 leq B_i , S_i leq 10^9 , 1 leq T_i leq 10^7))

    题解

    首先我们可以得出盈利效率的计算方法是(ans=frac{sum Val}{sum T}),然后我们会发现这个题目就会和BZOJ的最小圈那道题目有点类似了。继续考虑到这道题目中(N)的范围比较的小,所以我们可以考虑稍微暴力一些的方法。实际上,对于仍以两个点(u)(v),如果我们强制让这两个点分别为某一次交易的起点和终点,那么这一次交易的利益就是确定了的,所以我们可以之间从(u)(v)连一条(val)为这次交易的利益(如果是负的就不用连了),(T)为这两点之间的最短路的边,然后我们就可以转化成最小圈那题做了。

    Code:

    #include<bits/stdc++.h>
    using namespace std;
    const int M=10005;
    const int N=105;
    typedef long long ll;
    #define int ll
    typedef pair<ll,int>P;
    #define fi first
    #define se second
    #define mk make_pair
    
    int n,m,nk,tot;
    ll B[N][N*30],S[N][N*30];
    ll dis[N][N],Mp[N][N];
    struct edge {
      int to,nxt;
      ll w;
    }E[M];
    int head[N];
    void Addedge(int u,int v,ll w) {
      E[++tot].to=v;E[tot].nxt=head[u];head[u]=tot;E[tot].w=w;
    }
    
    queue<int>Q;
    ll di[N],inq[N],cnt[N],vis[N];
    int Spfa() {
      while(!Q.empty()) Q.pop();
      memset(cnt,0,sizeof cnt);memset(di,0,sizeof di);
      for(int i=1;i<=n;i++) Q.push(i),inq[i]=1;
      while(!Q.empty()) {
        int o=Q.front();Q.pop();
        cnt[o]++;
        if(cnt[o]>n) return 1;
        inq[o]=0;
        for(int i=head[o];~i;i=E[i].nxt) {
          int to=E[i].to;
          if(di[to]<=di[o]+E[i].w) {
        di[to]=di[o]+E[i].w;
        if(!inq[to]) {
          inq[to]=1;
          Q.push(to);
        }
          }
        }
      }
      return 0;
    }
    
    int Check(ll ret) {
      memset(head,-1,sizeof head);
      tot=0;
      for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
          if(i==j||Mp[i][j]<0) continue;
          Addedge(i,j,Mp[i][j]-ret*dis[i][j]);
        }
      }
      return Spfa();
    }
    
    signed main() {
      scanf("%lld%lld%lld",&n,&m,&nk);
      for(int i=1;i<=n;i++) {
        for(int j=1;j<=nk;j++) {
          scanf("%lld%lld",&B[i][j],&S[i][j]);
        }
      }
      memset(dis,0x3f,sizeof dis);
      for(int i=1,u,v;i<=m;i++) {
        ll t;
        scanf("%lld%lld%lld",&u,&v,&t);
        dis[u][v]=min(dis[u][v],t);
      }
      for(int k=1;k<=n;k++) {
        for(int i=1;i<=n;i++) {
          for(int j=1;j<=n;j++) {
        dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
          }
        }
      }
      for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
          if(dis[i][j]>1e10||i==j) continue;
          Mp[i][j]=0;
          for(int k=1;k<=nk;k++) {
        if(B[i][k]==-1||S[j][k]==-1) continue;
        Mp[i][j]=max(Mp[i][j],S[j][k]-B[i][k]);
          }
        }
      }
      ll L=0,R=1e9,ans=0;
      while(L<=R) {
        ll Mid=(L+R)>>1;
        if(Check(Mid)) L=Mid+1,ans=Mid;
        else R=Mid-1;
      }
      printf("%lld
    ",ans);
      return 0;
    }
    
    
  • 相关阅读:
    foreach_and_函数
    集合
    二维数组
    二维数组的操作
    字符串类型的一些操作
    数组循环的操作及思路
    数组操作
    js各种获取当前窗口页面宽度、高度的方法
    Jquery 获取 radio选中值,select选中值
    jQuery效果:隐藏、显示、切换、滑动、淡入淡出、动画
  • 原文地址:https://www.cnblogs.com/Apocrypha/p/9885043.html
Copyright © 2011-2022 走看看