【SDOI 2013】【BZOJ 3130】费用流

来源:互联网 发布:管家婆辉煌软件 编辑:程序博客网 时间:2024/06/06 18:56

这题的第一问是一个裸最大流,不多说了,关键在于第二问。首先有一个结论,Bob一定把费用加在一条边上,于是我们就可以二分每条边的流量,验证是否能得到最大流即可

code:

#include<iostream>#include<cstdio>#include<cstring>#define inf 0x7fffffffusing namespace std;int n,m,p,e,ei;int point[101],next[2001];int cur[101],pre[101],gap[101],lev[101];struct hp{int u,v;double c;}a[2001],ai[2001];void add(int x,int y,double c){e++; a[e].u=x; a[e].v=y; a[e].c=c; next[e]=point[x]; cur[x]=point[x]=e;e++; a[e].u=y; a[e].v=x; a[e].c=0; next[e]=point[y]; cur[y]=point[y]=e;}void addi(int x,int y,double c){ei++; ai[ei].u=x; ai[ei].v=y; ai[ei].c=c;ei++; ai[ei].u=y; ai[ei].v=x; ai[ei].c=0;}double ISAP(int vs,int vt){memset(lev,0,sizeof(lev));      memset(gap,0,sizeof(gap));      memset(pre,0,sizeof(pre));      int i,v,u=vs,minl;double maxt=0,aug;      bool f=false;      gap[0]=vt-vs+1;      while (lev[vs]<vt)        {          f=false;          for (v=cur[u];v!=0;v=next[v])            if (lev[u]==lev[a[v].v]+1&&a[v].c>0)              {f=true; cur[u]=v; break;}          if (f)            {              pre[a[v].v]=v;              u=a[v].v;              if (u==vt)                {                  aug=inf;                  for (i=v;i!=0;i=pre[a[i].u])                    if (a[i].c<aug)                      aug=a[i].c;                  maxt+=aug;                  for (i=v;i!=0;i=pre[a[i].u])                    {                      a[i].c-=aug;                      a[i^1].c+=aug;                    }                  u=vs;                }            }          else            {              minl=vt;              for (i=point[u];i!=0;i=next[i])                if (minl>lev[a[i].v]&&a[i].c>0)                  minl=lev[a[i].v];              gap[lev[u]]--;              if (gap[lev[u]]==0) break;              lev[u]=minl+1;              cur[u]=point[u];              gap[lev[u]]++;              if (u!=vs) u=a[pre[u]].u;             }        }      return maxt; }int main(){int i,x,y;double t,ans,l,r,mid,c,maxn=0;e=ei=1;scanf("%d%d%d",&n,&m,&p);for (i=1;i<=m;++i)  {    scanf("%d%d%lf",&x,&y,&c);    add(x,y,c);     addi(x,y,c);    maxn=max(maxn,c);  }ans=ISAP(1,n);printf("%d\n",(int)ans);l=0; r=maxn;while (r-l>1e-6)  {  memset(point,0,sizeof(point));  memset(cur,0,sizeof(cur));  memset(next,0,sizeof(point)); e=1;    mid=(l+r)/2;    for (i=2;i<=2*m+1;++i)      if (i%2==0) add(ai[i].u,ai[i].v,min(mid,ai[i].c));    t=ISAP(1,n); if (t==ans) r=mid-(1e-6); else l=mid+(1e-6);  }printf("%0.4lf\n",l*p);}


0 0