zoukankan      html  css  js  c++  java
  • 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
    ",r);
    104 }
    View Code
  • 相关阅读:
    【转】Android实战技巧:ViewStub的应用
    3.11 返回数据到前一个Activity
    在用android日志的时候老是弹出一个窗口,内容为:"Copy" did not complete normally. Please see the log 和 什么函数,能达到和android手机上按“返回”键一样的效果?
    Windows下的Android模拟器设置内存大小
    AlertDialog.Builder对话框类的用法(二)
    android版计算器
    【转】Android中字符串的拆分split
    readelf
    6200 uboot 测试版分析(二)
    cpp
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/12260815.html
Copyright © 2011-2022 走看看