题解报告——星际战争

题目传送门

题目描述

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: 复制
2 2
3 10
4 6
0 1
1 1
输出样例#1: 复制
1.300000

说明

【样例说明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 }

猜你喜欢

转载自www.cnblogs.com/genius777/p/9694968.html