zoukankan      html  css  js  c++  java
  • 题解报告——星际战争

    题目传送门

    题目描述

    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 }

  • 相关阅读:
    前端-JavaScript
    前端-HTML
    Python源程序(.py)转换为可执行文件(.exe)
    进程
    算法之动态规划问题
    算法之斐波那契数列
    贪心算法找零问题
    算法之迷宫问题
    数据结构相关知识
    常用排序算法
  • 原文地址:https://www.cnblogs.com/genius777/p/9694968.html
Copyright © 2011-2022 走看看