zoukankan      html  css  js  c++  java
  • bzoj 5403 Marshland

    $n leq 50$

    sol:

    放一个在 $x$ 处拐弯的 $L$ 形石头相当于在水平和垂直方向上各选一个与 $x$ 相邻的点,全局不能重复选

    最小化危险度,相当于满足这些限制的情况下石头盖住的点危险度越大越好,而石头有各种各样的限制,考虑费用流

    这是一个“只能增广 m 次的最大费用可行流”问题,我们增广到 m 次或者找出来的最长路为负即可

    为了满足“不重复选”,可以拆点,每个入点向出点连流量 1,费用为危险度的边

    因为每个危险点左右和上下各能选一个,相当于“每头牛都要分到一瓶可乐和一份午饭”(忘了这道题题号了...),可以把每个不危险的点分成“可乐”和“午饭”两类

    因为选的两个不危险的点行数奇偶性不同,所以可以考虑按行数奇偶把非危险点分成两类

    $S space ightarrow space 每个行数为奇数的非危险点 space ightarrow space 相邻的入点$

    $相邻的出点 space ightarrow space 每个行数为偶数的非危险点 space ightarrow space T$

    以上两类边流量 1,费用 0

    然后愉快的流

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1;char ch = getchar();
        for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
        for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
        return x * f;
    }
    const int maxn = 100010,maxm = 300010,oo = 2147483647;
    struct ZKW
    {
        int head[maxn], nx[maxn], inq[maxn], vis[maxn], dis[maxn];
        int n, m, s, t, ans, cost;
        queue<int> q;
        struct Edge
        {
            int from, to, caps, cost;
            Edge(){}
            Edge(int _1, int _2, int _3, int _4) : from(_1), to(_2), caps(_3), cost(_4){}
        }es[maxm];
        ZKW(){memset(head, -1, sizeof(head));}
        void setn(int _){n = _;}
        void AddEdge(int u, int v, int w, int c)
        {
            es[m] = Edge(u, v, w, c); nx[m] = head[u]; head[u] = m++;
            es[m] = Edge(v, u, 0, -c); nx[m] = head[v]; head[v] = m++;
        }
        bool BFS()
        {
            for(int i = 0;i <= n;i++)dis[i] = -oo;
            dis[t] = 0;inq[t] = 1;q.push(t);
            while(!q.empty())
            {
                int now = q.front();q.pop();
                for(int i = head[now]; i != -1; i = nx[i])
                {
                    Edge& e = es[i^1];
                    if(e.caps && dis[e.from] < dis[now] + e.cost)
                    {
                        dis[e.from] = dis[now] + e.cost;
                        if(!inq[e.from])
                        {
                            inq[e.from] = 1;
                            q.push(e.from);
                        }
                    }
                }
                inq[now] = 0;
            }
            if(dis[s] > 0){cost = dis[s];return 1;}
            return 0;
        }
        int DFS(int u, int a)
        {
            if(u == t || !a)return ans += cost * a, a;
            if(vis[u])return 0; vis[u] = 1;
            int flow = 0, f;
            for(int i = head[u]; i != -1; i = nx[i])
            {
                Edge& e = es[i];
                if(dis[e.to] == dis[u] - e.cost && (f = DFS(e.to, min(e.caps, a))))
                {
                    e.caps -= f; es[i^1].caps += f;
                    a -= f; flow += f;
                    if(!a)return flow;
                }
            }
            return flow;
        }
        int MaxCostFlow(int _s, int _t, int tms)
        {
            s = _s, t = _t;
            int flow = 0, f;
            for(int i = 1; i <= tms; i++) if(BFS()) {memset(vis, 0, sizeof(vis)); flow += DFS(s, oo);}
            return flow;
        }
    } sol;
    int n, m, k, s, t, ans;
    int mat[160][60],mem[160][160][5],dfn,b[maxn];
    inline int pos(int x, int y, int type)
    {
        return n * n * (type - 1) + (x - 1) * n + y;
    }
    int main()
    {
        n = read(), m = read(), k = read();
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++) mat[i][j] = read();
        s = 0, t = n * n * 2 + 1;
        sol.setn(t + 1);
        for(int i = 1; i <= k; i++)
        {
            int x = read(), y = read();
            b[pos(x, y, 1)] = 1;
        }
         
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
            {
                ans += mat[i][j];
                if(b[pos(i, j, 1)])continue;
                if((i + j) & 1)
                    sol.AddEdge(pos(i, j, 1), pos(i, j, 2), 1, mat[i][j]);
                else
                {
                    if(i & 1)
                    {
                        sol.AddEdge(s, pos(i, j, 1), 1, 0);
                        if(i > 1) sol.AddEdge(pos(i, j, 1), pos(i - 1, j, 1), 1, 0);
                        if(j > 1) sol.AddEdge(pos(i, j, 1), pos(i, j - 1, 1), 1, 0);
                        if(i < n) sol.AddEdge(pos(i, j, 1), pos(i + 1, j, 1), 1, 0);
                        if(j < n) sol.AddEdge(pos(i, j, 1), pos(i, j + 1, 1), 1, 0);
                    }
                    else
                    {
                        sol.AddEdge(pos(i, j, 1), t, 1, 0);
                        if(i > 1) sol.AddEdge(pos(i - 1, j, 2),pos(i, j, 1), 1, 0);
                        if(j > 1) sol.AddEdge(pos(i, j - 1, 2),pos(i, j, 1), 1, 0);
                        if(i < n) sol.AddEdge(pos(i + 1, j, 2), pos(i, j, 1), 1, 0);
                        if(j < n) sol.AddEdge(pos(i, j + 1, 2), pos(i, j, 1), 1, 0);
                    }
                }
            }
         
        sol.MaxCostFlow(s, t, m);
        cout << ans - sol.ans << endl;  
    }
    View Code

    不知道为什么 在限制增广次数的时候 ZKW 的多路增广是错的

  • 相关阅读:
    2-3树
    B树
    负载均衡的算法种类
    String源码分析
    实现一个List集合中的某个元素的求和
    就是通过事件方法,在window.loaction.href里追加了参数字符串
    九大内置对象及四个域对象的总结
    BigDecimal add方法问题:调用add后,求和结果没变
    java中List元素移除元素的那些坑
    Java序列化和反序列化,你该知道得更多
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10277399.html
Copyright © 2011-2022 走看看