BZOJ 3993 [SDOI 2015] 星际战争 解题报告

首先我们可以二分答案。

假设当前二分出来的答案是 $Ans$ ,那么我们考虑用网络流检验:

设武器为 $X$,第 $i$ 个武器的攻击力为 $B_i$;

设机器人为 $Y$,第 $i$ 个机器人的装甲为 $A_i$;

设 $Map[i][j]$ 表示第 $i$ 个机器人是否能攻击第 $j$ 号机器人。

设源为 $S$,汇为 $T$,现在考虑连边:

  • $S\rightarrow X_i$,容量为 $Ans * B_i$;
  • $Y_i\rightarrow T$,容量为 $A_i$;
  • $\forall (i,j),Map[i][j]=1:X_i\rightarrow Y_j$,容量为 $\infty$

然后跑网络流,假设最大流为 $M$,那么看是否有:$M=\sum A_i$。

如果是,那么说明当前答案是满足的,更新上界,否则更新下界。

毕竟 Gromah 太弱,只会做水题。

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <algorithm>
  6 using namespace std;
  7 typedef long double LD;
  8 #define N 50 + 5
  9 #define M 100000 + 5
 10 #define INF 1e9
 11 #define eps 1e-9
 12  
 13 int n, m, S, T, sum, tot;
 14 int A[N], B[N];
 15 int Head[N << 1], q[N << 1], Dfn[N << 1];
 16 bool Map[N][N];
 17 LD l = 0.0, r;
 18  
 19 struct Edge
 20 {
 21     int next, node;
 22     LD flow;
 23 }h[M];
 24  
 25 inline void addedge(int u, int v, LD fl)
 26 {
 27     h[++ tot].next = Head[u], Head[u] = tot;
 28     h[tot].node = v, h[tot].flow = fl;
 29     h[++ tot].next = Head[v], Head[v] = tot;
 30     h[tot].node = u, h[tot].flow = 0;
 31 }
 32  
 33 inline bool BFS()
 34 {
 35     for (int i = S; i <= T; i ++)
 36         Dfn[i] = 0;
 37     int l = 1, r = 1;
 38     q[1] = S, Dfn[S] = 1;
 39     while (l <= r)
 40     {
 41         int z = q[l ++];
 42         for (int i = Head[z]; i; i = h[i].next)
 43         {
 44             int d = h[i].node;
 45             LD p = h[i].flow;
 46             if (p < eps || Dfn[d]) continue ;
 47             Dfn[d] = Dfn[z] + 1;
 48             q[++ r] = d;
 49             if (d == T) return 1;
 50         }
 51     }
 52     return 0;
 53 }
 54  
 55 inline LD dinic(int z, LD inflow)
 56 {
 57     if (z == T || inflow < eps) return inflow;
 58     LD ret = inflow, flow;
 59     for (int i = Head[z]; i; i = h[i].next)
 60     {
 61         int d = h[i].node;
 62         LD p = h[i].flow;
 63         if (Dfn[d] != Dfn[z] + 1) continue ;
 64         flow = dinic(d, min(p, ret));
 65         ret -= flow;
 66         h[i].flow -= flow, h[i ^ 1].flow += flow;
 67         if (ret < eps) return inflow;
 68     }
 69     if (fabs(inflow - ret) < eps) Dfn[z] = -1;
 70     return inflow - ret;
 71 }
 72  
 73 inline bool Judge(LD k)
 74 {
 75     tot = 1;
 76     for (int i = S; i <= T; i ++)
 77         Head[i] = 0;
 78     for (int i = 1; i <= m; i ++)
 79         addedge(S, i, k * B[i]);
 80     for (int i = 1; i <= n; i ++)
 81         addedge(i + m, T, A[i]);
 82     for (int i = 1; i <= m; i ++)
 83         for (int j = 1; j <= n; j ++)
 84             if (Map[i][j]) addedge(i, j + m, INF);
 85     LD res = 0.0;
 86     while (BFS())
 87         res += dinic(S, INF);  
 88     return fabs(res - sum) < eps;
 89 }
 90  
 91 int main()
 92 {
 93     #ifndef ONLINE_JUDGE
 94         freopen("3993.in", "r", stdin);
 95         freopen("3993.out", "w", stdout);
 96     #endif
 97      
 98     scanf("%d%d", &n, &m);
 99     S = 0, T = n + m + 1;
100     for (int i = 1; i <= n; i ++)
101     {
102         scanf("%d", A + i);
103         r += A[i];
104         sum += A[i];
105     }
106     for (int i = 1; i <= m; i ++)
107         scanf("%d", B + i);
108     for (int i = 1; i <= m; i ++)
109         for (int j = 1; j <= n; j ++)
110             scanf("%d", Map[i] + j);
111     while (l + 1e-4 < r)
112     {
113         LD mid = (l + r) / 2;
114         if (Judge(mid)) r = mid;
115             else l = mid;
116     }
117     printf("%.4lf\n", (double) l);
118      
119     #ifndef ONLINE_JUDGE
120         fclose(stdin);
121         fclose(stdout);
122     #endif
123     return 0;
124 }
3993_Gromah

 

posted @ 2015-04-15 21:14  Gromah  阅读(638)  评论(0编辑  收藏  举报