APIO2017 商旅

Posted Apocrypha

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于APIO2017 商旅的主要内容,如果未能解决你的问题,请参考以下文章

APIO2017听课笔记关键词

apio2017游记

APIO2017懵逼记

游记CTSC&APIO2017

龙行商旅十八般武艺

bzoj4898商旅