zoukankan      html  css  js  c++  java
  • bzoj3993 [SDOI2015]星际战争

    Description

    (3333) 年,在银河系的某星球上, X军*和Y军*正在激烈地作战。在战斗的某一阶段,Y军*一共*遣了 (N) 个巨型机器人进攻X军*的阵地,其中第i个巨型机器人的装甲值为 (A_i) 。当一个巨型机器人的装甲值减少到 (0) 或者以下时,这个巨型机器人就被摧毁了。X军*有 (M) 个激光武器,其中第 (i) 个激光武器每秒可以削减一个巨型机器人 (B_i) 的装甲值。激光武器的攻击是连续的。这种激光武器非常奇怪,一个激光武器只能攻击一些特定的敌人。Y军*看到自己的巨型机器人被X军*一个一个消灭,他们急需下达更多的指令。为了这个目标,Y军*需要知道X军*最少需要用多长时间才能将Y军*的所有巨型机器人摧毁。但是他们不会计算这个问题,因此向你求助。

    Input

    第一行,两个整数, (N,M)
    第二行,(N) 个整数,(A_1,A_2…A_N)
    第三行,(M) 个整数,(B_1,B_2…B_M)
    接下来的 (M) 行,每行 (N) 个整数,这些整数均为 (0) 或者 (1) 。这部分中的第 (i) 行的第 (j) 个整数为 (0) 表示第 (i) 个激光武器不可以攻击第 (j) 个巨型机器人,为 (1) 表示第 (i) 个激光武器可以攻击第 (j) 个巨型机器人。

    Output

    一行,一个实数,表示X军*要摧毁Y军*的所有巨型机器人最少需要的时间。输出结果与标准答案的绝对误差不超过 (10^{-3}) 即视为正确。

    Sample Input

    2 2
    3 10
    4 6
    0 1
    1 1

    Sample Output

    1.300000

    HINT

    对于全部的数据,(1le N, Mle 50,1le A_ile 10^5,1le B_ile 1000) ,输入数据保证X军*一定能摧毁Y军*的所有巨型机器人

    Solution

    azi只会做傻逼题
    二分+最大流
    每次二分一个答案 (x) ,如下重新建图:

    • (S) 往每个武器连边,流量为 (x imes B_i)
    • 每个怪兽往 (T) 连边,流量为 (A_i)
    • 如果武器 (i) 可以攻击怪兽 (j)(i)(j) 连边,流量为 (INF)
    #include<bits/stdc++.h>
    using namespace std;
    
    #define N 1000
    #define eps (1e-9)
    #define INF (1e9)
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define lb long double
     
    inline int read() {
    	int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
    	while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
    }
    
    inline void write(int x) {
    	if (!x) { putchar('0'); return; } if (x < 0) putchar('-'), x = -x;
    	char buf[20] = ""; int top = 0; while (x) buf[++top] = x % 10 + '0', x /= 10; while (top) putchar(buf[top--]);
    }
    
    int n, m;
    int A[N], B[N], sum;
    struct edge { int v, next; lb c; }e[1000005];
    int head[N], tot, S, T;
    bool Map[N][N];
    int dep[N], q[N];
    
    inline void add(int u, int v, lb c) {
    	e[++tot] = edge{ v, head[u], c }; head[u] = tot;
    	e[++tot] = edge{ u, head[v], 0 }; head[v] = tot;
    }
    
    inline bool bfs() {
    	int l = 1, r = 1;
    	memset(dep, 0, sizeof dep); q[r] = S, dep[S] = 1;
    	while (l <= r) {
    		int u = q[l++];
    		for (int i = head[u]; i; i = e[i].next) {
    			int v = e[i].v; lb c = e[i].c;
    			if (c < eps || dep[v]) continue;
    			dep[v] = dep[u] + 1, q[++r] = v;
    			if (v == T) return 1;
    		}
    	}
    	return 0;
    }
    
    double dfs(int u, lb dis) {
    	if (!(u ^ T) || dis < eps) return dis;
    	for (int i = head[u]; i; i = e[i].next) {
    		int v = e[i].v; lb c = e[i].c;
    		if ((dep[v] ^ dep[u] + 1) || c < eps) continue;
    		lb d = dfs(v, min(dis, c));
    		if (d < eps) continue;
    		e[i].c -= d, e[i ^ 1].c += d;
    		return d;
    	}
    	return 0.0;
    }
    
    bool check(lb x) {
    	memset(head, 0, sizeof head); tot = 1;
    	rep(i, 1, m) add(S, i, x * B[i]);
    	rep(i, 1, n) add(i + m, T, A[i]);
    	rep(i, 1, m) rep(j, 1, n) if (Map[i][j]) add(i, j + m, INF);
    	lb ans = 0.0;
    	while (bfs()) ans += dfs(S, INF);
    	return fabs(ans - sum) < eps;
    }
    
    int main() {
    	scanf("%d%d", &n, &m); T = n + m + 1;
    	rep(i, 1, n) A[i] = read(), sum += A[i];
    	rep(i, 1, m) B[i] = read();
    	rep(i, 1, m) rep(j, 1, n) Map[i][j] = read();
    	lb l = 0.0, r = sum * 1.0;
    	while (l + 1e-4 < r) { lb mid = (l + r) / 2; if (check(mid)) r = mid; else l = mid; }
    	printf("%.4lf", (double)l);
    	return 0;
    }
    
  • 相关阅读:
    JSP简单练习-数组应用实例
    Android中的动画具体解释系列【4】——Activity之间切换动画
    php学习之道:WSDL具体解释(三)
    破解电信光猫(个人真实经验)
    POj 1879 Tempus et mobilius Time and motion (模拟+群)
    使用mysql-mmm实现MySQL高可用集群
    德克萨斯扑克_百度百科
    姜饼屋_百度百科
    阿根廷探戈----中英文对照
    波尔卡舞_百度百科
  • 原文地址:https://www.cnblogs.com/aziint/p/8416465.html
Copyright © 2011-2022 走看看