题目
Description
3333年,在银河系的某星球上,X军团和Y军团正在激烈地作战。在战斗的某一阶段,Y军团一共派遣了
个巨型机器人进攻X军团的阵地,其中第
个巨型机器人的装甲值为
。当一个巨型机器人的装甲值减少到
或者以下时,这个巨型机器人就被摧毁了。X团有
个激光武器,其中第
个激光武器每秒可以削减一个巨型机器人
的装甲值。激武器的攻击是连续的。这种激光武器非常奇怪,一个激光武器只能攻击一些特定的敌人。Y军团看到自己的巨型机器人被X军团一个一个消灭,他们急需下达更多的指令。为了这个目标,Y军团需要知道X军团最少需要用多长时间才能将Y军团的所有巨型机器人摧毁。但是他们不会计算这个问题,因此向你求助。
Input
第一行,两个整数,
、
。
第二行,
个整数,
、
、…、
。
第三行,
个整数,
、
、…、
。
接下来的
行,每行
个整数,这些整数均为0
或者1
。这部分中的第
行的第
个整数为0
表示第
个激光武器不可以攻击第
个巨型机器人,为1
表示第
个激光武器可以攻击第
个巨型机器人。
Output
一行,一个实数,表示X军团要摧毁Y军团的所有巨型机器人最少需要的时间。输出结果与标准答案的绝对误差不超过
即视为正确。
Sample Input
2 2
3 10
4 6
0 1
1 1
Sample Output
1.300000
Hint
战斗开始后的前0.5秒,激光武器1攻击2号巨型机器人,激光武器2攻击1号巨型机器人。1号巨型机器人被完全摧毁,2号巨型机器人还剩余8的装甲值;接下来的0.8秒,激光武器1、2同时攻击2号巨型机器人。2号巨型机器人被完全摧毁。
Data constraint
对于全部的数据,
,
,
,输入数据保证X军团一定能摧毁Y军团的所有巨型机器人。
分析
看了提示才发现可以分配小数时间给每个敌人。
二分时间
,注意精度问题。
每个武器是独立的,把源点向每个武器连流量为
的边,这样就控制了它的攻击时间;每个武器
向它能攻击的机器人
连流量为
的边;每个机器人
向汇点连流量为
(即打爆它的时间)。跑Dinic就好了。
代码
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read(){
int x=0;bool f=0;char c=getchar();
while(c<'0'||c>'9') f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return f?-x:x;
}
#define MAXN 100
#define INF 1e7
#define eps 1e-6
int N,M;
int A[MAXN+5],B[MAXN+5];
bool P[MAXN+5][MAXN+5];
struct Edge{
double w;
int v,Next;
Edge(){}
inline Edge(int x,double y,int z){
v=x,w=y,Next=z;
}
}E[MAXN*MAXN+5];
int ecnt,Adj[MAXN*2+5];
inline void AddEdge(int u,int v,double w){
E[ecnt]=Edge(v,w,Adj[u]),Adj[u]=ecnt++;
E[ecnt]=Edge(u,0,Adj[v]),Adj[v]=ecnt++;
}
int Cur[MAXN*2+5];
int Dist[MAXN*2+5];
bool bfs(int S,int T){
for(int i=0;i<=N+M+1;i++)
Cur[i]=Adj[i],Dist[i]=INF;
queue<int> Q;
Dist[S]=0,Q.push(S);
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int i=Adj[u];i!=-1;i=E[i].Next){
int v=E[i].v;
if(abs(E[i].w)>eps&&Dist[v]>Dist[u]+1){
Dist[v]=Dist[u]+1;
Q.push(v);
}
}
}
return Dist[T]<INF;
}
double dfs(int u,int T,double Min){
if(abs(Min)<=eps||u==T)
return Min;
double Now=0,Rest=Min;
for(int i=Cur[u];i!=-1;i=E[i].Next){
Cur[u]=i;
int v=E[i].v;
if(Dist[v]==Dist[u]+1){
if(abs(Now=dfs(v,T,min(Rest,E[i].w)))>eps){
Rest-=Now;
E[i].w-=Now;
E[i^1].w+=Now;
if(abs(Rest)<eps)
break;
}
}
}
return Min-Rest;
}
double Dinic(int S,int T){
double MaxFlow=0;
while(bfs(S,T))
MaxFlow+=dfs(S,T,INF);
return MaxFlow;
}
int Sum;
bool Check(double expt){
//暴力重建
ecnt=0;
memset(Adj,-1,sizeof Adj);
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
if(P[i][j])
AddEdge(i,j+M,INF);
for(int i=1;i<=M;i++)
AddEdge(0,i,expt*B[i]);
for(int i=1;i<=N;i++)
AddEdge(i+M,N+M+1,A[i]);
return abs(Dinic(0,N+M+1)-Sum)<=eps;
}
int main(){
N=read(),M=read();
for(int i=1;i<=N;i++)
Sum+=(A[i]=read());
for(int i=1;i<=M;i++)
B[i]=read();
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
P[i][j]=read();
double Left=0,Right=INF;
for(int i=1;i<=100;i++){
double Mid=(Left+Right)/2;
if(Check(Mid))
Right=Mid;
else
Left=Mid;
}
printf("%f",Right);
return 0;
}