zoukankan      html  css  js  c++  java
  • [SDOI 2015] 星际战争

    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=3993

    [算法]

             首先发现问题具有单调性 , 不妨二分答案mid 

             考虑网络流 :

             将源点向每个"激光武器”连一条流量为mid * Bi的边

             将每个“激光武器”向每个其可以攻击的“机器人”连一条流量为正无穷的边

             将每个“机器人”向汇点连一条流量为Ai的边

             判断是否满流即可

             时间复杂度 : O(dinic(N + M , M ^ 2) * logV)

    [代码]

            为避免精度误差 , 可以在整数域上进行二分 , 最后以浮点数形式输出

            

    #include<bits/stdc++.h>
    using namespace std;
    #define N 510
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const ll inf = 1e15;
    
    struct edge
    {
            int to;
            ll w;
            int nxt;
    } e[N * N * 5];
    
    int n , m , tot , S , T;
    int dep[N] , head[N] , g[N][N];
    ll a[N] , b[N];
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline void addedge(int u , int v , ll w)
    {
            ++tot;
            e[tot] = (edge){v , w , head[u]};
            head[u] = tot;
            ++tot;
            e[tot] = (edge){u , 0 , head[v]};
            head[v] = tot;
    }
    inline bool bfs()
    {
            queue< int > q;
            for (int i = 1; i <= T; ++i)
                    dep[i] = -1;
            q.push(S);
            dep[S] = 1;
            while (!q.empty())
            {
                    int cur = q.front();
                    q.pop();
                    for (int i = head[cur]; i; i = e[i].nxt)
                    {
                            int v = e[i].to;
                            ll w = e[i].w;
                            if (w > 0 && dep[v] == -1)
                            {
                                    dep[v] = dep[cur] + 1;
                                    q.push(v);
                                    if (v == T) return true;
                            }
                    }
            }
            return false;
    }
    inline ll dinic(int u , ll flow)
    {
            ll k , rest = flow;
            if (u == T)
                    return flow;
            for (int i = head[u]; i && rest; i = e[i].nxt)
            {
                    int v = e[i].to;
                    ll w = e[i].w;
                    if (dep[v] == dep[u] + 1 && w)
                    {
                            k = dinic(v , min(w , rest));
                            e[i].w -= k;
                            e[i ^ 1].w += k;
                            if (!k) dep[v] = 0;
                            rest -= k;
                    }
            }
            return flow - rest;
    }
    inline bool check(ll mid)
    {
            S = n + m + 1 , T = S + 1;
            for (int i = 1; i <= T; ++i) head[i] = 0;
            for (int i = 1; i <= tot; ++i) e[i].nxt = 0;
            tot = 1;
            for (int i = 1; i <= m; ++i) addedge(S , i , b[i] * mid);
            for (int i = 1; i <= m; ++i)
            {
                    for (int j = 1; j <= n; ++j)
                    {
                            if (g[i][j])
                                    addedge(i , j + m , inf);
                    }
            }
            ll sum = 0;
            for (int i = 1; i <= n; ++i) 
            {
                    addedge(i + m , T , a[i]);
                    sum += a[i];
            }
            ll res = 0;
            while (bfs())
            {
                    while (double flow = dinic(S , inf)) res += flow;
            }
            return res == sum;
    }
    
    int main()
    {
            
            scanf("%d%d" , &n , &m); 
            for (int i = 1; i <= n; ++i) 
            {
                    scanf("%lld" , &a[i]);
                    a[i] *= 1000;
            }
            for (int i = 1; i <= m; ++i) scanf("%lld" , &b[i]);
            for (int i = 1; i <= m; ++i)
            {
                    for (int j = 1; j <= n; ++j)
                    {
                            scanf("%d" , &g[i][j]);
                    }
            }
            ll l = 0 , r = inf , ans = 0;
            while (l <= r)
            {
                    int mid = (l + r) >> 1;
                    if (check(mid))
                    {
                            ans = mid;
                            r = mid - 1;
                    } else l = mid + 1;
            }
            printf("%.6lf
    " , (double)(ans / 1000.0));
            
            return 0;
        
    }
  • 相关阅读:
    poj 2763 Housewife Wind
    hdu 3966 Aragorn's Story
    poj 1655 Balancing Act 求树的重心
    有上下界的网络流问题
    URAL 1277 Cops and Thieves 最小割 无向图点带权点连通度
    ZOJ 2532 Internship 网络流求关键边
    ZOJ 2760 How Many Shortest Path 最大流+floyd求最短路
    SGU 438 The Glorious Karlutka River =) 拆点+动态流+最大流
    怎么样仿写已知网址的网页?
    5-10 公路村村通 (30分)
  • 原文地址:https://www.cnblogs.com/evenbao/p/10549250.html
Copyright © 2011-2022 走看看