SDOI2013 费用流

题目链接:戳我

emmmm就是在可行的最大流里面让最大边最小。我们可以进行二分+限流然后跑dinic,看是否能跑满即可。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#define eps 1e-6
#define S 1
#define T n
#define MAXN 100010
#define INF 1e9
using namespace std;
int n,m,t=1,p;
int head[MAXN<<1],dep[MAXN],cur[MAXN<<1];
double maxx;
struct Edge{int nxt,to;double dis;}edge[MAXN<<1],pre[MAXN<<1];
inline void add(int from,int to,double dis)
{
  edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,head[from]=t;
  edge[++t].nxt=head[to],edge[t].to=from,edge[t].dis=0,head[to]=t;
}
inline bool bfs()
{
  queue<int>q;
  memset(dep,0x3f,sizeof(dep));
  memcpy(cur,head,sizeof(head));
  q.push(S);dep[S]=0;
  while(!q.empty())
  {
    int u=q.front();q.pop();
    //printf("u=%d\n",u);
    for(int i=head[u];i;i=edge[i].nxt)
    {
      int v=edge[i].to;
      //printf("v=%d dep[v]=%d dis=%.2lf\n",v,dep[v],edge[i].dis);
      if(dep[v]==0x3f3f3f3f&&edge[i].dis>eps)
        dep[v]=dep[u]+1,q.push(v);
    }
    //puts("");
  }
  if(dep[T]==0x3f3f3f3f) return false;
  return true;
}
inline double dfs(int x,double f)
{
  if(f<eps||x==T) return f;
  double w,used=0;
  for(int i=cur[x];i;i=edge[i].nxt)
  {
    int v=edge[i].to;
    cur[x]=i;
    if(dep[v]==dep[x]+1&&(w=dfs(v,min(edge[i].dis,f))))
    {
      edge[i].dis-=w,edge[i^1].dis+=w;
      f-=w,used+=w;
      if(f<eps) break;
    }
  }
  return used;
}
inline double dinic()
{
  double cur_ans=0;
  while(bfs()) cur_ans+=dfs(S,INF);
  return cur_ans;
}
inline bool check(double limit)
{
  //cout<<"limit="<<limit<<endl;
  for(int i=2;i<=t;i++) edge[i].dis=min(pre[i].dis,limit);
  //for(int i=2;i<=t;i++) cout<<edge[i].dis<<" ";
  double cur_ans=dinic();
  //cout<<endl<<"cur_ans="<<cur_ans<<endl;
  if(maxx-cur_ans<eps) return true;
  return false;
}
int main()
{
  #ifndef ONLINE_JUDGE
  freopen("ce.in","r",stdin);
  #endif
  scanf("%d%d%d",&n,&m,&p);
  for(int i=1;i<=m;i++)
  {
    int u,v,w;
    scanf("%d%d%d",&u,&v,&w);
    add(u,v,w);
  }
  for(int i=2;i<=t;i++) pre[i].dis=edge[i].dis;
  maxx=dinic();
  double l=0,r=50000.0;
  //cout<<"maxx="<<maxx<<endl;
  while(r-l>eps)
  {
    double mid=(l+r)/2;
    if(check(mid)) r=mid;
    else l=mid;
  }
  printf("%d\n",(int)maxx);
  printf("%.4lf\n",l*(p*1.0));
  return 0;
}

posted @ 2019-02-14 22:14  风浔凌  阅读(98)  评论(0编辑  收藏  举报