题目描述
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个巨型机器人。
输出格式:
一行,一个实数,表示X军团要摧毁Y军团的所有巨型机器人最少需要的时间。输出结果与标准答案的绝对误差不超过10-3即视为正确。
输入输出样例
说明
【样例说明1】
战斗开始后的前0.5秒,激光武器1攻击2号巨型机器人,激光武器2攻击1号巨型机器人。1号巨型机器人被完全摧毁,2号巨型机器人还剩余8的装甲值;
接下来的0.8秒,激光武器1、2同时攻击2号巨型机器人。2号巨型机器人被完全摧毁。
对于全部的数据,1<=N, M<=50,1<=Ai<=10510^5105,1<=Bi<=1000,输入数据保证X军团一定能摧毁Y军团的所有巨型机器人
【思路分析】
看到这道题,我们发现机器人血量不同,武器攻击力不同,讨论起来贼麻烦,提问则是最少需要的时间,发现这就是求最大时间最小,不难想到我们可以二分攻击时间T,每次使所有机器都攻击T时间,然后判断是否可行。
那么我们怎么判断可行呢,我们观察数据,n,m小于50,真是一个奇奇妙妙的范围,状压太大,线性的又太小,感觉这就是网络流通常的数据范围吧(不伦不类的。。。)
发现我们可以用最大流写一个可行流判断流量是否满流即可。
每个机器人向T连容量为Ai的边,S向每个激光武器连容量为Bi*T的边,武器与机器人之间连INF的边,即可AC。。。
最后值得注意的是,我们的时间T的精度误差为1e-3,那么我们就将二分的值乘上1000,最后再除以1000,即可保留3位小数了
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 typedef long long ll; 8 void read(int &v) 9 { 10 int f;char ch; 11 while(!isdigit(ch=getchar())&&ch!='-'); ch=='-'?(f=-1,v=0):(f=1,v=ch-'0'); 12 while(isdigit(ch=getchar())) v=v*10+ch-'0';v=v*f; 13 } 14 const int N=105; 15 const ll INF=1e18+7; 16 struct sd{ 17 int next,to; 18 ll val,w; 19 sd(){}; 20 sd(int a,int b,ll c){next=a,to=b,val=c;} 21 }edge[N*N<<1]; 22 queue<int> que; 23 int head[N],dep[N],n,m,s,t,cnt=1; 24 ll sum; 25 bool vis[N]; 26 void add_edge(int from,int to,ll w) 27 { 28 edge[++cnt]=sd(head[from],to,w),head[from]=cnt; 29 edge[++cnt]=sd(head[to],from,0),head[to]=cnt; 30 } 31 bool bfs() 32 { 33 memset(dep,0,sizeof(dep)); 34 dep[s]=1;que.push(s); 35 while(!que.empty()) 36 { 37 int v=que.front();que.pop(); 38 for(int i=head[v];i;i=edge[i].next) 39 { 40 int to=edge[i].to; 41 if(!dep[to]&&edge[i].w) 42 dep[to]=dep[v]+1,que.push(to); 43 } 44 } 45 return dep[t]; 46 } 47 int dfs(int v,ll flow) 48 { 49 if(v==t||flow==0) return flow; 50 for(int i=head[v];i;i=edge[i].next) 51 { 52 int to=edge[i].to; 53 if(dep[to]==dep[v]+1&&edge[i].w) 54 { 55 ll ff=dfs(to,min(flow,edge[i].w)); 56 if(!ff) continue; 57 edge[i].w-=ff; 58 edge[i^1].w+=ff; 59 return ff; 60 } 61 } 62 return 0; 63 } 64 bool check(ll tt) 65 { 66 for(int i=1;i<=cnt;i++) edge[i].w=edge[i].val; 67 for(int i=head[s];i;i=edge[i].next) 68 { 69 int to=edge[i].to; 70 edge[i].w=edge[i].val*tt; 71 } 72 ll ans=0; 73 while(bfs()) 74 { 75 ll d=0; 76 while(d=dfs(s,INF)) ans+=d; 77 } 78 return ans>=sum; 79 } 80 int main() 81 { 82 int w; 83 read(m),read(n),s=0,t=n+m+1; 84 for(int i=1;i<=m;i++) read(w),add_edge(n+i,t,1ll*1000*w),sum+=1ll*1000*w; 85 for(int i=1;i<=n;i++) read(w),add_edge(s,i,1ll*w); 86 for(int i=1;i<=n;i++) 87 for(int j=1;j<=m;j++) 88 { 89 read(w); 90 if(w) add_edge(i,j+n,INF); 91 } 92 ll l=0,r=1000000000ll,ans; 93 while(l<=r) 94 { 95 ll mid=l+r>>1; 96 if(check(mid)) ans=mid,r=mid-1; 97 else l=mid+1; 98 } 99 printf("%lf",(double)ans/1000); 100 return 0; 101 }