题目
3333年,在银河系的某星球上,X军团和Y军团正在激烈地作战。在战斗的某一阶段,Y军团一共派遣了N个巨型机器人进攻X军团的阵地,其中第i个巨型机器人的装甲值为Ai。当一个巨型机器人的装甲值减少到0或者以下时,这个巨型机器人就被摧毁了。X军团有M个激光武器,其中第i个激光武器每秒可以削减一个巨型机器人Bi的装甲值。激光武器的攻击是连续的。这种激光武器非常奇怪,一个激光武器只能攻击一些特定的敌人。Y军团看到自己的巨型机器人被X军团一个一个消灭,他们急需下达更多的指令。为了这个目标,Y军团需要知道X军团最少需要用多长时间才能将Y军团的所有巨型机器人摧毁。但是他们不会计算这个问题,因此向你求助。
第一行,两个整数,N、M。
第二行,N个整数,A1、A2…AN。
第三行,M个整数,B1、B2…BM。
接下来的M行,每行N个整数,这些整数均为0或者1。这部分中的第i行的第j个整数为0表示第i个激光武器不可以攻击第j个巨型机器人,为1表示第i个激光武器可以攻击第j个巨型机器人。
对于30%的数据,1<=N, M<=5;
对于全部的数据,1<=N, M<=50,1<=Ai<=105,1<=Bi<=1000,输入数据保证X军团一定能摧毁Y军团的所有巨型机器人。
题意
就是有m个机关枪,n个机器,每个机关枪每秒可以造成ai点伤害。
每个机器也有bi点体力值,问多少秒后可以把全部的机器干掉。每个机关枪有指定的机器打。
秒数有可能为小数。
分析
我们先来分析题目要求什么?
其实就是要求每个机关枪打的最大值最小。
也就是二分。
现在我们考虑如何判定。
其实也很简单,我们把这个问题转换成网络流的问题。
从源点连到每个机关枪连容量为当前二分的mid*a[i]
然后每个机关枪向它们可以打的机器连maxlongint
机器再向汇点连bi。
最后只用判断最大流是否为∑bi就行了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxlongint 2147483647
using namespace std;
const int N=60,M=10000;
const double eps=0.00001;
int n,m,ai[N],bi[N],b[M],las[M],nex[M],nu,t,x,ma,d[M],a[M];
double mid,f[M],re[M],sum;
void insert(int x,int y,int z){
b[++nu]=y;nex[nu]=las[x];las[x]=nu;f[nu]=z;re[nu]=z;
b[++nu]=x;nex[nu]=las[y];las[y]=nu;f[nu]=0;
}
bool bfs(){
int l=0,r=1;a[1]=0;
memset(d,0,sizeof(d));d[0]=1;
while (l<r){
for(int p=las[a[++l]];p;p=nex[p]){
if (!d[b[p]]&&f[p]>eps) {
a[++r]=b[p];d[b[p]]=d[a[l]]+1;
}
}
}
return d[t];
}
double ditch(int x,double y){
if (x==t) return y;
double ll=0;
for(int p=las[x];p;p=nex[p]){
if (d[b[p]]==d[x]+1&&f[p]>eps){
double u=ditch(b[p],min(y,f[p]));
if (u>eps){
y-=u;ll+=u;f[p]-=u;f[p^1]+=u;
if (y<eps) break;
}
}
}
if (ll<eps) d[x]=-1;
return ll;
}
bool check(double x){
for(int i=1;i<=m;i++)re[i*2]=x*bi[i]*1.0,re[i*2+1]=0;
double ans=0;
for(int i=2;i<=nu;i++) f[i]=re[i]*1.0;
while (bfs()) ans+=ditch(0,maxlongint);
return sum-ans<eps;
}
int main(){
scanf("%d%d",&n,&m);nu=1;t=n+m+1;
ma=0,sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&ai[i]);
sum+=ai[i];
}
for(int i=1;i<=m;i++){
scanf("%d",&bi[i]);
insert(0,i,bi[i]);
ma=max(ma,bi[i]);
}
for(int i=1;i<=n;i++)insert(i+m,t,ai[i]);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++){
scanf("%d",&x);
if (x) insert(i,j+m,maxlongint);
}
double l=0,r=sum/ma;
while(r-l>eps){
mid=(l+r)/2*1.0;
if (check(mid)) r=mid-eps;
else l=mid+eps;
}
printf("%.6lf\n",l);
}