Luogu P3324 [SDOI2015]星际战争

二分+最大流

首先考虑二分答案

然后可以发现对于已知时间,判断是否可以将所有机器人摧毁可以用网络流

建立源点和汇点,源点向每一个激光武器连一条容量为$time*b[i]$的边,表示该激光武器在$time$时间下最多能产生的伤害为$time*b[i]$

每一个机器人向汇点连一条容量为$a[i]$的边,表示每一个机器人最多能承受的伤害

中间每一个激光武器向其能攻击的机器人连一条容量为$inf$的边

然后跑最大流,若可以跑出$\sum a[i]$,那么该时间可以将所有与机器人摧毁,更新二分边界

  1 #include <bits/stdc++.h>
  2 #define inf 1e9
  3 using namespace std;
  4 const int N=210,M=6100;
  5 int n,m,s,t,tot,first[N],nxt[M],point[M],nrl[N],d[N];
  6 int vi[N][N];
  7 double data[M],a[N],b[N],sum;
  8 void add_edge(int x,int y,double z)
  9 {
 10     tot++;
 11     nxt[tot]=first[x];
 12     first[x]=tot;
 13     point[tot]=y;
 14     data[tot]=z;
 15     tot++;
 16     nxt[tot]=first[y];
 17     first[y]=tot;
 18     point[tot]=x;
 19     data[tot]=0;
 20 }
 21 bool bfs()
 22 {
 23     queue <int> q;
 24     for (int i=s;i<=t;i++)
 25     {
 26         d[i]=inf;
 27         nrl[i]=first[i];
 28     }
 29     d[s]=0;q.push(s);
 30     while (!q.empty())
 31     {
 32         int x=q.front();
 33         q.pop();
 34         for (int i=first[x];i!=-1;i=nxt[i])
 35         {
 36             int u=point[i];
 37             if (data[i]>0 && d[u]>d[x]+1)
 38             {
 39                 d[u]=d[x]+1;
 40                 if (u==t) return true;
 41                 q.push(u);
 42             }
 43         }
 44     }
 45     return false;
 46 }
 47 double dfs(int x,double flow)
 48 {
 49     if (x==t) return flow;
 50     double sum=0;
 51     for (int i=nrl[x];i!=-1;i=nxt[i])
 52     {
 53         int u=point[i];
 54         if (data[i]>0 && d[u]==d[x]+1)
 55         {
 56             double tmp=dfs(u,min(flow,data[i]));
 57             flow-=tmp;sum+=tmp;
 58             data[i]-=tmp;data[i^1]+=tmp;
 59             if (flow<=0) return sum;
 60         }
 61         nrl[x]=nxt[i];
 62     }
 63     return sum;
 64 }//使用dinic跑最大流
 65 bool check(double mid)
 66 {
 67     tot=-1;
 68     memset(first,-1,sizeof(first));
 69     memset(nxt,-1,sizeof(nxt));
 70     s=0;t=n+m+1;//同上建边
 71     for (int i=1;i<=m;i++) add_edge(s,i,mid*b[i]);
 72     for (int i=1;i<=n;i++) add_edge(m+i,t,a[i]);
 73     for (int i=1;i<=m;i++)
 74     {
 75         for (int j=1;j<=n;j++)
 76         {
 77             if (vi[i][j]) add_edge(i,m+j,inf);
 78         }
 79     }
 80     double ans=0;
 81     while (bfs()) ans+=dfs(s,inf);
 82     return ans==sum;//判断是否跑满
 83 }
 84 int main()
 85 {
 86     scanf("%d%d",&n,&m);
 87     for (int i=1;i<=n;i++) scanf("%lf",&a[i]);
 88     for (int i=1;i<=m;i++) scanf("%lf",&b[i]);
 89     for (int i=1;i<=m;i++)
 90     {
 91         for (int j=1;j<=n;j++)
 92           scanf("%d",&vi[i][j]);
 93     }
 94     sum=0;
 95     for (int i=1;i<=n;i++) sum+=a[i];
 96     double l=0,r=1e8;
 97     while ((r-l)>=1e-8)
 98     {
 99         double mid=(l+r)/2;
100         if (check(mid)) r=mid;
101         else l=mid;
102     }
103     printf("%.6lf\n",r);
104 }
View Code

 

posted @ 2020-02-04 19:54  SevenDawns  阅读(169)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end