[9018_2101]保卫萝卜
题目描述
一群怪物正向着你的萝卜出发……
这群怪物共有N只,第i只怪物的HP为Ai,当怪物的HP减少到0时,这个怪物就被摧毁了。现在你有M座防御塔,其中第i个防御塔每秒可以减少一只怪物Bi点的HP。由于怪物有不同的属性,所以某些怪物会对某些防御塔免疫。
你的任务是计算至少需要多少时间才能消灭所有的怪物。
输入
第一行两个正整数N,M
第二行N个正整数,表示A1~An
第三行M个正整数,表示B1~Bn
接下来是一个M*N的矩阵,矩阵中每个元素均为0或1。第i行第j列为1表示第i座防御塔可以攻击第j只怪物,为0表示第j只怪物对第i座防御塔的攻击免疫。
输出
一行,一个实数,表示所需的最小时间。保留3位小数
样例输入
2 2 3 10 4 6 0 1 1 1
样例输出
1.300
提示
前0.5s "Times New Roman"">,防御塔1攻击2号怪物,防御塔2 "Times New Roman"">攻击1号怪物。1号怪物被摧毁,2 "Times New Roman"">号怪物剩下8点HP。
接下来0.8s "Times New Roman"">,1号和2号防御塔同时攻击2 "Times New Roman"">号怪物。2号怪物被摧毁。
对于全部的数据,1<=N,M<=50 "Times New Roman"">,1<=Ai<=10^5 "Times New Roman"">,1<=Bi<=10^4 "Times New Roman"">,输入数据确保不存在同时对所有防御塔免疫的怪物
二分答案+最大流check
二分击杀所有怪物所用时间
从源点s向每座塔连一条容量为t*b[i]的边,表示塔在t秒内的总输出
从每座塔向不能免疫它的攻击的怪物连一条容量为INF的边,表示该塔可以攻击怪物
从每个怪物向汇点连一条容量为怪物血量的边,表示该怪物能承受这么多的输出
对于每个二分出来的t,检查是否满流
若满流,表示怪物全部被击杀,可以减少时间,否则,表示有怪物还活着,需增加时间
注意浮点误差
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define eps 1e-5 #define INF 999999999 using namespace std; int h[1000],to[100000],nxt[100000],k=1,level[1000],iter[1000],s,t,n,m;double tot=0.0; int H=0,T=0,que[100000],A[51],B[51];double ca[100000]; bool mp[1000][1000]; void ins(int u,int v,double cap) { nxt[++k]=h[u];to[k]=v;ca[k]=cap;h[u]=k; nxt[++k]=h[v];to[k]=u;ca[k]=0;h[v]=k; } void bfs() { memset(level,0,sizeof(level)); H=T=0;que[T++]=s;level[s]=1; while(H!=T) { int u=que[H++]; for(int i=h[u];i;i=nxt[i]) { if(!level[to[i]]&&abs(ca[i])>=eps) { level[to[i]]=level[u]+1;que[T++]=to[i]; } } } } double dfs(int u,double f) { if(u==t)return f; double used=0,w; for(int &i=iter[u];i;i=nxt[i]) { if(abs(ca[i])>=eps&&level[to[i]]==level[u]+1) { w=f-used;w=dfs(to[i],min(w,ca[i])); if(abs(w)>=eps) { ca[i]-=w;ca[i^1]+=w;used+=w;if(used==f)return f; } } } return used; } double dinic() { double flow=0; for(;;) { for(int i=1;i<=n+m+2;i++)iter[i]=h[i]; bfs();if(!level[t])return flow; flow+=dfs(s,INF); } return flow; } double erfen(double L,double R) { while(R-L>eps) { double mid=(L+R)/2; k=1;memset(h,0,sizeof(h)); for(int i=1;i<=n;i++)ins(i+m,t,(double)A[i]); for(int i=1;i<=m;i++)ins(s,i,(double)mid*B[i]); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++)ins(i,j+m,(double)INF); double ff=dinic(); if(abs(ff-tot)<eps)R=mid; else L=mid; } return L; } int main() { scanf("%d%d",&n,&m);s=n+m+1,t=n+m+2; for(int i=1;i<=n;i++){scanf("%d",&A[i]);tot+=(double)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++) { int q;scanf("%d",&q);mp[i][j]=1; } printf("%.3lf",erfen(0.0,5000000.0)); return 0; }