[费用流 高精度类 分数类] AOJ 2691 Cost Performance Flow

根据费用流增广的特点
费用和流量肯定是一条凸的分段函数
考虑的答案的几何意义
就是一个点到这条函数的最短距离 直接一段段求就好了
ps 这个题输出小数不就好了 结果输分数
就拉了个分数类 不会__int128 就又拉了个高精度类
总之这道题让我很桑心啊

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
typedef long double ld;

class Int{
#define BASE 1000000000
public:
  typedef long long value;
  void New(size_t l){
    if (a!=NULL)delete[] a;a=new value[l];
    len=1;a[0]=0;sign=1;
  }
  Int():a(NULL),base(BASE){New(1);}
  Int(value x):a(NULL),base(BASE){New(1);*this=x;}
  Int(value x,value _base):a(NULL),base(_base){New(1);*this=x;}
  Int(const Int &B):a(NULL),base(BASE){New(1);*this=B;}
  ~Int(){delete[] a;}
  Int& operator =(value x){
    size_t l=1;for (value x1=max(x,-x);x1>=base;++l,x1/=base);New(l);
    if (x<0)x=-x,sign=0;else sign=1;
    len=0;while (x)a[len++]=x%base,x/=base;
    if (!len)a[len++]=0;
    return *this;
  }
  Int& operator =(const Int &A){
    New(A.len);len=A.len;memcpy(a,A.a,sizeof(value)*len);
    base=A.base;sign=A.sign;return *this;
  }
  friend Int operator -(Int A){A.sign=1-A.sign;return A;}
  bool operator !(){if (len==1&&a[0]==0)return 1;else return 0;}
  friend Int operator +(Int A,Int B){
    if (A.sign!=B.sign){B.sign=1-B.sign;return A-B;}
    if (A.base!=B.base)
      if (A.base>B.base)B.set_base(A.base);
      else A.set_base(B.base);
    Int res;res.set_base(A.base); int len=A.len>B.len?A.len:B.len;
    res.New(len+1);res.sign=A.sign;
    memset(res.a,0,(len+1)*sizeof(value));
    for (int i=0;i<len;++i){
      if (i<A.len)res.a[i]+=A.a[i];
      if (i<B.len)res.a[i]+=B.a[i];
    }
    for (int i=0;i<len;++i)
      if (res.a[i]>=res.base)++res.a[i+1],res.a[i]-=res.base;
    if (res.a[len])res.len=len+1;else res.len=len;
    if (!res)res.sign=1;return res;
  }
  friend Int operator -(Int A,Int B){
    if (A.sign!=B.sign){B.sign=1-B.sign;return A+B;}
    if (A.base!=B.base)
      if (A.base>B.base)B.set_base(A.base);
      else A.set_base(B.base);
    if (small(A,B))swap(A,B),A.sign=1-A.sign;
    Int res;res.set_base(A.base); int len=A.len>B.len?A.len:B.len;
    res.New(len);res.sign=A.sign;
    memset(res.a,0,len*sizeof(value));
    for (int i=0;i<len;++i){
      if (i>=B.len)res.a[i]+=A.a[i];
      else res.a[i]+=A.a[i]-B.a[i];
      if (res.a[i]<0)res.a[i]+=res.base,--res.a[i+1];
    }
    while (len>1&&!res.a[len-1])--len;res.len=len;
    if (!res)res.sign=1;return res;
  }
  friend Int operator *(Int A,Int B){
    if (A.base!=B.base)
      if (A.base>B.base)B.set_base(A.base);
      else A.set_base(B.base);
    Int res;res.set_base(A.base); int len=A.len+B.len;
    res.New(len);res.sign=(A.sign==B.sign);
    memset(res.a,0,len*sizeof(value));
    for (int i=0;i<A.len;++i)
      for (int j=0;j<B.len;++j){
    res.a[i+j]+=A.a[i]*B.a[j];
    res.a[i+j+1]+=res.a[i+j]/res.base;
    res.a[i+j]%=res.base;
      }
    /*
      for (int i=0;i<A.len;++i)
      for (int j=0;j<B.len;++j)res.a[i+j]+=A.a[i]*B.a[j];
      for (int i=0;i<len-1;++i)res.a[i+1]+=res.a[i]/res.base,res.a[i]%=res.base;
    */
    while (len>1&&!res.a[len-1])--len;res.len=len;
    return res;
  }
  friend pair<Int,Int> divide(Int A,Int B){
    if (!B){puts("error:div zero!");for (;;);}
    if (A.base!=B.base)
      if (A.base>B.base)B.set_base(A.base);
      else A.set_base(B.base);
    if (small(A,B))return make_pair(Int(0),A);
    Int C,D;C.set_base(A.base);D.set_base(A.base);C.New(A.len);C.len=A.len;
    bool Csign=(A.sign==B.sign),Dsign=A.sign;A.sign=B.sign=1;
    for (int i=A.len-1;i>=0;--i){
      C.a[i]=0;D=D*D.base;D.a[0]=A.a[i];
      int l=0,r=A.base-1,mid;
      while (l<r){
    mid=(l+r+1)>>1;
    if (small(B*mid,D+1))l=mid;
    else r=mid-1;
      }
      C.a[i]=l;D=D-B*l;
    }
    C.sign=Csign;D.sign=Dsign;if (!D)D.sign=1;
    while (C.len>1&&!C.a[C.len-1])--C.len;
    return make_pair(C,D);
  }
  Int operator /(value x){
    if (!x){puts("error:div zero!");for (;;);}
    value d=0;Int res;res.set_base(base);res.New(len);res.len=len;
    if (x<0)x=-x,res.sign=(sign==0);
    else res.sign=(sign==1);
    for (int i=len-1;i>=0;--i)
      d=d*base+a[i],res.a[i]=d/x,d%=x;
    while (res.len>1&&!res.a[res.len-1])--res.len;
    return res;
  }
  Int operator %(value x){
    value d=0;if (x<0)x=-x;
    for (int i=len-1;i>=0;--i)d=(d*base+a[i])%x;
    return d;
  }
  friend Int abs(Int A){A.sign=1;return A;}
  friend bool small(Int A,Int B){
    if (A.base!=B.base)
      if (A.base>B.base)B.set_base(A.base);
      else A.set_base(B.base);
    if (A.len!=B.len)return A.len<B.len;
    for (int i=A.len-1;i>=0;--i)
      if (A.a[i]!=B.a[i])return A.a[i]<B.a[i];
    return 0;
  }
  friend bool operator <(Int A,Int B){
    if (A.sign!=B.sign)return A.sign<B.sign;
    return A.sign==1?small(A,B):small(B,A);
  }
  friend bool operator ==(Int A,Int B){
    if (A.base!=B.base)
      if (A.base>B.base)B.set_base(A.base);
      else A.set_base(B.base);
    if (A.sign!=B.sign||A.len!=B.len)return 0;
    for (int i=0;i<A.len;++i)if (A.a[i]!=B.a[i])return 0;
    return 1;
  }
  friend bool operator !=(Int A,Int B){return !(A==B);}
  friend bool operator >(Int A,Int B){return !(A<B||A==B);}
  friend bool operator <=(Int A,Int B){return A<B||A==B;}
  friend bool operator >=(Int A,Int B){return A>B||A==B;}
  Int operator /(Int B){return divide(*this,B).first;}
  Int operator %(Int B){return divide(*this,B).second;}
  Int& operator +=(Int B){*this=*this+B;return *this;}
  Int& operator -=(Int B){*this=*this-B;return *this;}
  Int& operator *=(Int B){*this=*this*B;return *this;}
  Int& operator /=(Int B){*this=*this/B;return *this;}
  Int& operator %=(Int B){*this=*this%B;return *this;}
  Int& operator ++(){*this=*this+1;return *this;}
  Int& operator --(){*this=*this-1;return *this;}
  Int operator ++(int){Int res(*this);*this=*this+1;return res;}
  Int operator --(int){Int res(*this);*this=*this-1;return res;}
  Int operator +(value x){return *this+Int(x,this->base);}
  Int operator -(value x){return *this-Int(x,this->base);}
  Int operator *(value x){return *this*Int(x,this->base);}
  //Int operator /(value x){Int T;T=x;return *this/T;}
  //Int operator %(value x){Int T;T=x;return *this%T;}
  Int& operator *=(value x){*this=*this*x;return *this;}
  Int& operator +=(value x){*this=*this+x;return *this;}
  Int& operator -=(value x){*this=*this-x;return *this;}
  Int& operator /=(value x){*this=*this/x;return *this;}
  Int& operator %=(value x){*this=*this%x;return *this;}
  bool operator ==(value x){return *this==Int(x,this->base);}
  bool operator !=(value x){return *this!=Int(x,this->base);}
  bool operator <=(value x){return *this<=Int(x,this->base);}
  bool operator >=(value x){return *this>=Int(x,this->base);}
  bool operator <(value x){return *this<Int(x,this->base);}
  bool operator >(value x){return *this>Int(x,this->base);}
  friend Int gcd(Int x,Int y){
    Int t;int cnt=0;
    while (1){
      if (x<y)t=x,x=y,y=t;
      if (y==0){
    while (cnt--)x*=2;
    return x;
      }
      if (x%2==0&&y%2==0)x/=2,y/=2,++cnt;
      else if (x%2==0)x/=2;
      else if (y%2==0)y/=2;
      else {t=x;x=y;y=t-y;}
    }
  }
  void to_arr(char *c){
    char *c1=c;
    for (int i=0;i<len-1;++i)
      for (value x=a[i],b=base/10;b>=1;b/=10)*c1++='0'+x%10,x/=10;
    for (value x=a[len-1];x>0;x/=10)*c1++='0'+x%10;
    if (len==1&&a[len]==0)*c1++='0';
    if (sign==0)*c1++='-';*c1=0;reverse(c,c1);
  }
  void from_arr(char *c){
    size_t base_l=get_basel(),b=1;int cl=strlen(c);value x=0;
    New((cl+base_l-1)/base_l);len=0;
    if (*c=='-')sign=0,++c,--cl;else sign=1;
    while (--cl>=0){
      x+=(c[cl]-'0')*b;b*=10;if (b==base)a[len++]=x,x=0,b=1;
    }
    if (!len||x)a[len++]=x;
    while (len>1&&!a[len-1])--len;
  }
  void set_base(int _base){
    if (base==_base)return;
    char *c=new char[len*get_basel()+1];
    to_arr(c);base=_base;from_arr(c);
    delete[] c;
  }
  void set_basel(int _l){
    size_t _base=1;while (_l--)_base*=10;set_base(_base);
  }
  void read(){
    vector<char> s;char ch;
    scanf(" %c",&ch);if (ch=='-')s.push_back('-'),ch=getchar();
    for (;ch>='0'&&ch<='9';ch=getchar())s.push_back(ch);
    char *c=new char[s.size()+1];
    for (int i=0;i<s.size();++i)c[i]=s[i];c[s.size()]=0;
    from_arr(c);delete[] c;
    if (!*this)this->sign=1;
  }
  void print(){
    if (!sign)putchar('-');
    printf("%d",int(a[len-1]));
    for (int i=len-2;i>=0;--i){
      for (int j=base/10;j>=10;j/=10)
    if (a[i]<j)putchar('0');
    else break;
      printf("%d",(int)a[i]);
    }
  }
  void println(){print();putchar('\n');}
private:
  value *a,base;int len;bool sign;  //0="-"
  size_t get_basel()const{
    size_t res=0;for (int b=base/10;b>=1;b/=10,++res);
    return res;
  }
#undef BASE
};

namespace Frac{
  typedef long long vint;
  struct frac{
    frac(vint a=1,vint b=1);  
    virtual ~frac(){};  
    long double value()const;
    void sim();
    friend ostream& operator<<(ostream& os,frac& f);
    frac operator +(const frac& f)const;  
    frac operator -(const frac& f)const;  
    frac operator *(const frac& f)const;  
    frac operator /(frac f)const;  
    bool operator ==(const frac& f)const;  
    bool operator >(const frac& f)const;  
    bool operator <(const frac& f)const;  
    frac rev();
    void ChangeValue(vint a,vint b);
    vint u,d;
    bool neg;
  };
  vint Function(vint& a,vint& b)  {  
    vint r=a%b;  
    while(r) a=b,b=r,r=a%b; 
    return b;  
  }  
  ostream& operator<<(ostream& os,frac& f)  {  
    f.sim();  
    if(f.neg) os<<"-"<<f.u<<"/"<<f.d<<endl;  
    else os<<""<<f.u<<"/"<<f.d<<endl;  
    return os;  
  }  
  frac::frac(vint a, vint b):neg(false){ 
    while(b==0){ }  
    this->u=abs(a); this->d=abs(b);  
    if(a<0&&b<0) this->neg=false;  
    else if(a<0||b<0) this->neg=true;  
    else this->neg=false;  
    this->sim();  
  }  
  long double frac::value()const{  
    return this->u/(long double)d;  
  }  
  void frac::sim(){  
    vint a=u,b=d;  
    vint ret=Function(a,b);  
    u/=ret; d/=ret;  
  }  
  frac frac::operator +(const frac &f)const{  
    frac temp;  
    if(neg==f.neg){  
      temp.u=u*f.d+d*f.u; temp.d=d*f.d; temp.neg=neg;  
    }  
    else{  
      temp.u=abs(u*f.d-d*f.u); temp.d=abs(d*f.d);  
      if(this->value()>f.value())  
    temp.neg=neg;  
      else  
    temp.neg=f.neg;  
    }
    temp.sim();
    return temp;  
  }
  frac frac::operator -(const frac &f) const{  
    frac temp;  
    if(neg==f.neg){  
      temp.u=abs(u*f.d-d*f.u); temp.d=d*f.d;  
      if(value()>=f.value()) temp.neg=false;  
      else temp.neg=true;  
    }  
    else{ 
      temp.u=u*f.d+d*f.u; temp.d=d*f.d;  
      temp.neg=neg;  
    }  
    temp.sim();
    return temp;  
  }  
  frac frac::operator *(const frac &f) const{  
    frac temp;  
    temp.u=u*f.u; temp.d=d*f.d;
    if(neg==f.neg) temp.neg=false;  
    else temp.neg=true;
    temp.sim();
    return temp;  
  }  
  frac frac::operator /(frac f) const {  
    frac temp,r; r=f.rev(); temp=*this*r; 
    temp.sim();return temp;  
  }  
  frac frac::rev() {  
    frac temp;  
    temp.d=u; temp.u=d; temp.neg=neg;  
    return temp;  
  }  
  bool frac::operator ==(const frac &f) const{  
    if(neg!=f.neg) return false;  
    if(value()==f.value()) return true;  
    else return false;  
  }  
  bool frac::operator <(const frac &f) const{  
    if(neg==f.neg){ 
      if(value()<f.value()){  
    if(neg) return false;  
    else return true;  
      }  
      else if(value()>f.value()){  
    if(neg) return true;  
    else return false;  
      }  
      else return false;  
    }  
    else
      if(neg) return true;  
      else return false;  
  }  
  bool frac::operator >(const frac& f)const { 
    return (f<*this);  
  }  
  void frac::ChangeValue(vint a,vint b)  {  
    *this=frac(a,b);  
  }
}
using namespace Frac;

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(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=1005;

struct edge{
  int u,v,w,f,next;
}G[N<<1];
int head[N],inum=1;
inline void add(int u,int v,int w,int f,int p){
  G[p].u=u; G[p].v=v; G[p].w=w; G[p].f=f; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v,int w,int f){
  add(u,v,w,f,++inum); add(v,u,-w,0,++inum);
}

struct PP{
  ll x,y;
  PP(ll x=0,ll y=0):x(x),y(y) { }
  friend PP operator + (PP A,PP B){ return PP(A.x+B.x,A.y+B.y); }
  friend PP operator - (PP A,PP B){ return PP(A.x-B.x,A.y-B.y); }
  friend ll operator * (PP A,PP B){ return A.x*B.x+A.y*B.y; }
}pt[100005],p0;
int tot;

int n,m,S,T;

int dis[N],pre[N],ins[N];
int Q[5000005],l,r;
#define V G[p].v
inline bool SPFA(){
  l=r=-1;
  for (int i=1;i<=n;i++) dis[i]=1<<30,pre[i]=0,ins[i]=0;
  Q[++r]=S; dis[S]=0; ins[S]=1;
  while (l<r){
    int u=Q[++l]; ins[u]=0;
    for (int p=head[u];p;p=G[p].next)
      if (G[p].f && dis[V]>dis[u]+G[p].w){
    dis[V]=dis[u]+G[p].w; pre[V]=p;
    if (!ins[V]) Q[++r]=V,ins[V]=1;
      }
  }
  if (dis[T]==1<<30) return 0;
  int minv=1<<30;
  for (int p=pre[T];p;p=pre[G[p].u])
    minv=min(minv,G[p].f);
  for (int p=pre[T];p;p=pre[G[p].u])
    G[p].f-=minv,G[p^1].f+=minv;
  pt[++tot]=PP(pt[tot-1].x+minv,pt[tot-1].y+minv*dis[T]);
  return 1;
}

ld ans=1e20;
frac ax,ay;

inline void Solve(PP p1,PP p2,PP p0){
  ll r1=(p2-p1)*(p0-p1),r2=(p1-p2)*(p0-p2);
  frac x1=frac(p1.x,1),y1=frac(p1.y,1);
  frac x2=frac(p2.x,1),y2=frac(p2.y,1);
  frac x0=frac(p0.x,1),y0=frac(p0.y,1);
  if (r1>0 && r2>0){
    frac k=(y2-y1)/(x2-x1);
    frac x=(x0/k+y0+k*x1-y1)/(k+k.rev());
    frac y=k*(x-x1)+y1;
    ld dx=(x-x0).value();
    ld dy=(y-y0).value();
    ld d=dx*dx+dy*dy;
    if (d<ans)
      ans=d,ax=x,ay=y;
  }else if (r1<=0){
    ld dx=(x1-x0).value();
    ld dy=(y1-y0).value();
    ld d=dx*dx+dy*dy;
    if (d<ans)
      ans=d,ax=x1,ay=y1;
  }else {
    ld dx=(x2-x0).value();
    ld dy=(y2-y0).value();
    ld d=dx*dx+dy*dy;
    if (d<ans)
      ans=d,ax=x2,ay=y2;
  }
}

int main(){
  int _u,_v,_f,_w;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m); read(S); read(T);
  for (int i=1;i<=m;i++)
    read(_u),read(_v),read(_f),read(_w),link(_u,_v,_w,_f);
  pt[++tot]=PP(0,0);
  while (SPFA());
  p0=PP(pt[tot].x,0);
  if (tot==1)
    return printf("0/1\n"),0;
  for (int i=1;i<tot;i++)
    Solve(pt[i],pt[i+1],p0);
  frac dx=ax-pt[tot].x,dy=ay;
  Int a=dx.d,b=dx.u,c=dy.d,d=dy.u;
  a=a*a; b=b*b; c=c*c; d=d*d;
  Int ans_u=b*c+a*d,ans_d=a*c,g=gcd(ans_u,ans_d);
  ans_u/=g; ans_d/=g;
  ans_u.print(); putchar('/'); ans_d.print(); putchar('\n');
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值