传送门
SOL
首先思考dp,发现一个合法的方案限制太多,难以dp。
n
,
m
≤
50
n,m\le50
n,m≤50,有点网络流的味道
思考贪心,即在相同的时间内,让所有机器人的总输出尽量大,构造方案可以最大流;
建图:机器人向汇点连容量为装甲值的边,源点向激光炮连边,根据激光炮和机器人的攻击关系连容量为inf的边。
源点向
i
i
i激光炮连边容量为
b
i
∗
t
b_{i}*t
bi∗t,二分
t
t
t,判断总流量能否达到
∑
i
=
1
n
A
i
\sum_{i=1}^n A{i}
∑i=1nAi;
CODE
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define db double
#define cs const
cs int N=1e4+10,mov=50;
ll inf=1e18;
cs db eps=1e-7,eps2=1e-4;
int nxt[N],to[N],head[N],cnt=1,S,T,n,m,A;
ll w[N];
inline void _add(int u,int v,ll ww){
nxt[++cnt]=head[u];head[u]=cnt;to[cnt]=v;w[cnt]=ww;
}
//inline bool equal(cs db &a,cs db &b){
// return abs(a-b)<eps;
//}
namespace dinic{
int dep[N],cur[N];
db c[N];
inline bool bfs(){
for(int i=S;i<=T;++i)dep[i]=-1;
queue<int> q;
q.push(T);dep[T]=1;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=nxt[i]){
if(c[i^1]<eps)continue;
int v=to[i];
if(v==S){
dep[v]=dep[u]+1;
return 1;
}
if(dep[v]==-1){
dep[v]=dep[u]+1;
q.push(v);
}
}
}
return 0;
}
inline db dfs(int u,db f){
if(u==T)return f;
if(f<eps)return 0;
db tot=0,now=0;
for(int &i=cur[u];i;i=nxt[i]){
// cout<<to[i]<<' '<<f<<'\n';
if(c[i]<eps)continue;
int v=to[i];
if(dep[v]==dep[u]-1){
now=dfs(v,min(f-tot,c[i]));
if(!now)continue;
tot+=now;
c[i]-=now;c[i^1]+=now;
if(f-tot<eps)break;
}
}
return tot;
}
inline bool cflow(db t){
db ret=0;
for(int i=2;i<=cnt;++i)c[i]=1.0*w[i];
for(int i=head[S];i;i=nxt[i]){
c[i]=t*w[i];
}
while(bfs()){
for(int i=S;i<=T;++i)cur[i]=head[i];
ret+=dfs(S,inf);
}
return A-ret<eps;
}
}
signed main(){
sf("%d%d",&n,&m);
S=0;T=mov+n+1;
for(int i=1;i<=n;++i){
int num;sf("%d",&num);
_add(i+mov,T,num);
_add(T,i+mov,0);
A+=num;
}
for(int i=1;i<=m;++i){
int num;
sf("%d",&num);
_add(S,i,num);
_add(i,S,0);
}
for(int i=1;i<=m;++i){
for(int j=1;j<=n;++j){
int f;sf("%d",&f);
if(f){
_add(i,j+mov,inf);
_add(j+mov,i,0);
}
}
}
db l=0,r=5e6,mid;
// cout<<dinic::cflow(1.3)<<'\n';
while(l+eps2<r){
mid=(l+r)/2.0;
if(dinic::cflow(mid))r=mid;
else l=mid;
}
pf("%.3lf",l);
return 0;
}