zoukankan      html  css  js  c++  java
  • 【bzoj3993】[SDOI2015]星际战争 二分+最大流

    题目描述

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

    输入

    第一行,两个整数,N、M。

    第二行,N个整数,A1、A2…AN。
    第三行,M个整数,B1、B2…BM。
    接下来的M行,每行N个整数,这些整数均为0或者1。这部分中的第i行的第j个整数为0表示第i个激光武器不可以攻击第j个巨型机器人,为1表示第i个激光武器可以攻击第j个巨型机器人。

    输出

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

    样例输入

    2 2
    3 10
    4 6
    0 1
    1 1

    样例输出

    1.300000


    题解

    二分+最大流,apio讲过的题。

    设激光武器为xi,机器人为yi。

    二分时间mid,S->xi,容量为bi*mid(需要保留小数);xi->能够攻击的yi,容量为inf;yi->T,容量为ai。

    判断是否满流,并更新答案。

    由于二分的时间是小数,所以最好是限制迭代次数,达到次数后跳出循环即可。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define N 110
    #define M 100000
    #define inf 1000000000
    using namespace std;
    queue<int> q;
    double a[N] , b[N] , val[M];
    int n , m , p[N][N] , head[N] , to[M] , next[M] , cnt = 1 , s , t , dis[N];
    void add(int x , int y , double z)
    {
        to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
        to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
    }
    bool bfs()
    {
        int x , i;
        memset(dis , 0 , sizeof(dis));
        while(!q.empty()) q.pop();
        dis[s] = 1 , q.push(s);
        while(!q.empty())
        {
            x = q.front() , q.pop();
            for(i = head[x] ; i ; i = next[i])
            {
                if(val[i] > 0 && !dis[to[i]])
                {
                    dis[to[i]] = dis[x] + 1;
                    if(to[i] == t) return 1;
                    q.push(to[i]);
                }
            }
        }
        return 0;
    }
    double dinic(int x , double low)
    {
        if(x == t) return low;
        double temp = low , k;
        int i;
        for(i = head[x] ; i ; i = next[i])
        {
            if(val[i] > 0 && dis[to[i]] == dis[x] + 1)
            {
                k = dinic(to[i] , min(temp , val[i]));
                if(k <= 0) dis[to[i]] = 0;
                val[i] -= k , val[i ^ 1] += k;
                if((temp -= k) <= 0) break;
            }
        }
        return low - temp;
    }
    bool judge(double mid)
    {
        int i , j;
        double sum = 0;
        memset(head , 0 , sizeof(head)) , cnt = 1;
        for(i = 1 ; i <= m ; i ++ ) add(s , i , b[i] * mid);
        for(i = 1 ; i <= n ; i ++ ) add(i + m , t , a[i]) , sum += a[i];
        for(i = 1 ; i <= m ; i ++ )
            for(j = 1 ; j <= n ; j ++ )
                if(p[i][j])
                    add(i , j + m , inf);
        while(bfs()) sum -= dinic(s , inf);
        return sum <= 0;
    }
    int main()
    {
        int i , j , tot = 100;
        double l = 0 , r = 1000000 , mid;
        scanf("%d%d" , &n , &m) , s = 0 , t = n + m + 1;
        for(i = 1 ; i <= n ; i ++ ) scanf("%lf" , &a[i]);
        for(i = 1 ; i <= m ; i ++ ) scanf("%lf" , &b[i]);
        for(i = 1 ; i <= m ; i ++ )
            for(j = 1 ; j <= n ; j ++ )
                scanf("%d" , &p[i][j]);
        while(tot -- )
        {
            mid = (l + r) / 2;
            if(judge(mid)) r = mid;
            else l = mid;
        }
        printf("%.6lf
    " , r);
        return 0;
    }
    

     

  • 相关阅读:
    iOS
    iOS
    ios
    iOS
    ios
    ios
    iOS
    ios
    常用NSString的方法
    instancetype
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6999334.html
Copyright © 2011-2022 走看看