【二分答案】【最大流】bzoj3993 [Sdoi2015]星际战争

二分Time,
S->炮[i]:Time*b[i]

炮[i]->机器人[i]:INF

机器人[i]->T:a[i]。

判断是否满流。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define N 51
#define EPS 0.000001
#define INF 2147483647.0
typedef double db;
queue<int>q;
int n,m,a[N],b[N],sumv;
bool can[N][N];
int v[2*N*(N+1)],en,first[N*2+3],next[2*N*(N+1)];
db cap[2*N*(N+1)];
void AddEdge(int U,int V,db W)
{
    v[en]=V; cap[en]=W; next[en]=first[U]; first[U]=en++;
    v[en]=U; cap[en]=0; next[en]=first[V]; first[V]=en++;
}
int S,T,nn;
int d[N*2+3],cur[N*2+3];
bool bfs()
{
    memset(d,-1,sizeof(int)*(nn+1));
    d[S]=0;
    q.push(S);
    while(!q.empty())
      {
        int U=q.front(); q.pop();
        for(int i=first[U];i!=-1;i=next[i])
          if(d[v[i]]==-1&&cap[i]>EPS)
            {
              d[v[i]]=d[U]+1;
              q.push(v[i]);
            }
      }
    return d[T]!=-1;
}
db dfs(int U,db a)
{
    if(U==T||a<=EPS)
      return a;
    db Flow=0.0,f;
    for(int &i=cur[U];i!=-1;i=next[i])
      if(d[v[i]]==d[U]+1&&(f=dfs(v[i],min(a,cap[i])))>EPS)
        {
          cap[i]-=f;
          cap[i^1]+=f;
          Flow+=f;
          a-=f;
          if(a<=EPS)
            break;
        }
    if(Flow<=EPS) d[U]=-1;
    return Flow;
}
db MaxFlow()
{
    db Flow=0.0,tmp;
    while(bfs())
      {
        memcpy(cur,first,sizeof(int)*(nn+1));
        while((tmp=dfs(S,INF))>EPS) Flow+=tmp;
      }
    return Flow;
}
bool check(db Lim)
{
    memset(first,-1,sizeof(int)*(nn+1));
    en=0;
    for(int i=1;i<=m;++i)
      AddEdge(S,1+i,Lim*(db)b[i]);
    for(int i=1;i<=n;++i)
      AddEdge(1+m+i,T,(db)a[i]);
    for(int i=1;i<=m;++i)
      for(int j=1;j<=n;++j)
        if(can[i][j])
          AddEdge(1+i,1+m+j,INF);
    return fabs(MaxFlow()-(db)sumv)<=EPS?1:0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
      {
        scanf("%d",&a[i]);
        sumv+=a[i];
      }
    for(int i=1;i<=m;++i) scanf("%d",&b[i]);
    for(int i=1;i<=m;++i)
      for(int j=1;j<=n;++j)
        scanf("%d",&can[i][j]);
    S=1; T=nn=m+n+2;
    db l=0.0,r=5000000.0;
    while(r-l>EPS)
      {
        db mid=(l+r)/2.0;
        if(check(mid))
          r=mid-EPS;
        else
          l=mid+EPS;
      }
    printf("%lf
",l);
    return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/4430076.html