[分数规划 & FLOYD判正环] BZOJ4898[Apio2017] 商旅

答案是分数规划的形式

二分答案
就是求

witix

也就是

wixtix

用floyd判是否有正环就可以了

#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;

const int N=110;

int n,m,k;
int s[N][1010],b[N][1010];

ll w[N][N],t[N][N];

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
  char c=nc(); x=0; int f=1;
  for(;c>'9'||c<'0';c=nc())if(c=='-')f=-1;for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc()); x*=f;
}

namespace FLOYD{
  ll dis[N][N];

  bool check(ll x){
    memset(dis,-0x7f>>1,sizeof(dis));
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
    if(i!=j)
      dis[i][j]=w[i][j]-x*t[i][j];
    for(int k=1;k<=n;k++)
      for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
      dis[i][j]=max(dis[i][k]+dis[k][j],dis[i][j]);
    for(int i=1;i<=n;i++)
      if(dis[i][i]>=0) return true;
    return false;
  }
}

int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  read(n); read(m); read(k);
  for(int i=1;i<=n;i++)
    for(int j=1;j<=k;j++)
      read(b[i][j]),read(s[i][j]);
  memset(t,0x7f>>1,sizeof(t));
  for(int i=1,x,y,ti;i<=m;i++)
    read(x),read(y),read(ti),t[x][y]=min(t[x][y],(ll)ti);
  for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
    t[i][j]=min(t[i][j],t[i][k]+t[k][j]);
  for(int i=1;i<=k;i++){
    for(int x=1;x<=n;x++)
      for(int y=1;y<=n;y++)
    if(~b[x][i] && ~s[y][i]) w[x][y]=max(w[x][y],(ll)s[y][i]-b[x][i]);
  }
  int kk=FLOYD::check(2);
  ll L=1,R=1e9,mid,ans=0;
  while(L<=R) FLOYD::check(mid=L+R>>1)?L=(ans=mid)+1:R=mid-1;
  printf("%lld\n",ans);
  return 0;
}

你可能感兴趣的:(最短路,分数规划)