【二分答案】【最大流】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\n",l); return 0; }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/