您的位置:首页 > 其它

[BZOJ3993][SDOI2015]星际战争(二分答案+最大流)

2017-11-21 18:30 471 查看
先二分时间,记当前判断的时间为time。

建立源点和汇点,建图为:

1、∀1≤i≤M,由源点向第i个激光武器建一条容量为time∗Bi的边。

2、∀1≤i≤N,由第i个巨型机器人向汇点建一条容量为Ai的边。

3、∀1≤i≤M,1≤j≤N,如果第i个激光武器可以攻击第j个机器人,那么由第i个激光武器向第j个机器人连一条容量为∞的边。

跑一遍最大流,如果最大流等于∑Ni=1Ai,那么在time或比time更短的时间内,可以摧毁所有的机器人。

注意精度。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps = 1e-9, INF = 1e12;
const int M = 55, N = 2e5 + 5;
int n, m, a[M], b[M], ecnt = 1, nxt
, adj
, go
, lev
,
len, que
, cur
, S, T, g[M][M], sm; double cap
, Cap
;
void add_edge(int u, int v, double w) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt;
go[ecnt] = v; cap[ecnt] = w;
nxt[++ecnt] = adj[v]; adj[v] = ecnt;
go[ecnt] = u; cap[ecnt] = 0;
}
bool bfs() {
int i; for (i = S; i <= T; i++) lev[i] = -1, cur[i] = adj[i];
que[len = 1] = S; lev[S] = 0;
for (i = 1; i <= len; i++) {
int u = que[i];
for (int e = adj[u], v; e; e = nxt[e])
if (cap[e] > eps && lev[v = go[e]] == -1) {
que[++len] = v; lev[v] = lev[u] + 1;
if (v == T) return 1;
}
}
return 0;
}
double dinic(int u, double flow) {
if (u == T) return flow;
double res = 0, d = 0;
for (int &e = cur[u], v; e; e = nxt[e])
if (cap[e] > eps && lev[u] < lev[v = go[e]]) {
d = dinic(v, min(cap[e], flow - res));
if (d > eps) {
cap[e] -= d; cap[e ^ 1] += d;
res += d; if (fabs(flow - res) <= eps)
break;
}
}
if (fabs(flow - res) > eps) lev[u] = -1;
return res;
}
double solve() {
double ans = 0;
while (bfs()) ans += dinic(S, INF);
return ans;
}
void build(double tm) {
int i; for (i = 2; i <= ecnt; i++)
cap[i] = Cap[i];
for (i = 2; i <= (m << 1) + 1; i += 2)
cap[i] = tm * b[i >> 1];
}
double SOLVE() {
double l = 0, r = 1e9, mid = (l + r) / 2;
while (r - l >= eps) {
build(mid);
if (1.0 * sm - solve() < eps) r = mid;
else l = mid;
mid = (l + r) / 2;
}
return mid;
}
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
int main() {
int i, j; n = read(); m = read();
for (i = 1; i <= n; i++) a[i] = read(), sm += a[i];
for (i = 1; i <= m; i++) b[i] = read();
for (i = 1; i <= m; i++) for (j = 1; j <= n; j++)
g[i][j] = read(); S = 1; T = n + m + 2;
for (i = 2; i <= m + 1; i++) add_edge(S, i, 0);
for (i = m + 2; i < T; i++) add_edge(i, T, 1.0 * a[i - m - 1]);
for (i = 2; i <= m + 1; i++) for (j = m + 2; j < T; j++)
if (g[i - 1][j - m - 1]) add_edge(i, j, INF);
for (i = 2; i <= ecnt; i++) Cap[i] = cap[i];
printf("%.6lf\n", SOLVE());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: