zoukankan      html  css  js  c++  java
  • [洛谷P2472] [SCOI2007]蜥蜴

    题目链接:

    蜥蜴

    题目分析:

    一道网络流,先来分析一下问题:
    在一个(r*c)的图中分布了一些数,其他地方都用(0)填充,我们分别从指定的一些数出发,每次可以移动到周围距离为(d)以内的数上(或图外),原来的数会被(-1),任何时候数不能为负。各个数走法之间互相影响。问至多有多少个数出发能到达图外?

    把这个题的限制条件列出来一下吧:

    • 每个石柱只能站一只蜥蜴
    • 每个石柱最多被经过其高度次
    • 石柱与石柱之间,石柱与图边界之间要距离小于等于(d)才能到达

    首先我的角度是以每个石柱本身的限制条件入手。我们知道一个高度为(h)的石柱最多可以被经过(h)次(显然,蜥蜴是不走回头路的,因为这是对资源的浪费),而网络流的基本性质之一,是每条边最多将其上限流满(相当于有一个上限),那么可以考虑将石柱的高度作为网络流建图边上的限制。但是每个石柱是一个点,怎么办呢,我们就考虑把每个石柱拆点,把编号为(i)的点拆成(i)(i + r * c),然后把流入这个点的边全部接到(i)上,流出这个点的边全部接到(i+r*c)上,把限制加在两点之间的连边上(流量为(h))。这是对于石柱的处理,也是我认为这个问题中最关键的一步。

    剩下的就比较好办了。
    对于“每个石柱只能站一只蜥蜴”的限制条件,将“只能站一只”作为上界,源点向蜥蜴所在的每个石柱连边,边容量为(1)
    对于石柱和石柱之间,石柱与图边界之间距离小于等于(d)才能到达的限制条件,因为图很小,我们考虑直接暴力枚举两个点,如果两个点都有石柱且距离小于等于(d),那么我们直接考虑两个石柱之间连一条容量为(INF)的边:除了距离,没有别的限制条件了,而距离的限制条件已经判断过了,并且每个石柱的限制已经在拆点的过程中加上去了,所以容量不需要做其他的限制,直接连(INF)即可。对于到达边界的限制条件,我们同样连一条(INF)的边(和前面的原因类似),距离判断只需要判断横纵就行,因为根据勾股定理,横纵都比(d)大显然斜着也比(d)大。

    代码:

    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    #define INF (1000000000 + 7)
    #define N (10005 + 5)
    #define M (100000 + 5)
    #define int long long
    using namespace std;
    inline int read(){
        int cnt = 0, f = 1; char c;
        c = getchar();
        while (!isdigit(c)) {
            if(c == '-') f = -f;
            c = getchar();
        }
        while (isdigit(c)) {
            cnt = cnt * 10 + c - '0';
            c = getchar();
        }	
        return cnt * f;
    }
    int r, c, d, tot = 1, n;
    int S, T;
    int first[M], nxt[M], to[M], flow[M];
    int mapp[N][N], a[N][N];
    int dep[M], cnt[M];
    char lizard[N][N];
    inline void Add(int x, int y, int z) {
        nxt[++tot] = first[x], first[x] = tot, to[tot] = y, flow[tot] = z;
        nxt[++tot] = first[y], first[y] = tot, to[tot] = x, flow[tot] = 0;
    } 
    inline bool pd(int i, int j) {
        if (i <= d || j <= d) return true;
        if (r - i + 1 <= d || c - j + 1 <= d) return true;
        return false;
    }
    inline void build() {
        S = 1;
        for (register int i = 1; i <= r; i++)
            for (register int j = 1; j <= c; j++)
                a[i][j] = ++tot;
    
        for (register int i = 1; i <= r; i++)
            scanf("%s", lizard[i] + 1);
        for (register int i = 1; i <= r; i++)
            for (register int j = 1; j <= c; j++)
                mapp[i][j] = lizard[i][j] - '0';
                
        T = r * c * 2 + 2, tot = 1;
    
        for (register int i = 1; i <= r; i++)
                scanf("%s", lizard[i] + 1);	
        
        for (register int i = 1; i <= r; i++)
            for (register int j = 1; j <= c; j++) 
                if (mapp[i][j]) {
                    Add(a[i][j], a[i][j] + r * c, mapp[i][j]);
                    if (pd(i, j)){
                         Add(a[i][j] + r * c, T, INF);
    //					 cout<<i<<" "<<j<<endl;
                    }
                }
                
        for (register int i = 1; i <= r; i++)
            for (register int j = 1; j <= c; j++) 
                for (register int k = 1; k <= r; k++) 
                    for (register int p = 1; p <= c; p++) {
                        if (i == k && j == p) continue;
                        if (mapp[i][j] && mapp[k][p])
                        if ((i - k) * (i - k) + (j - p) * (j - p) <= d * d)
                            Add(a[i][j] + r * c, a[k][p], INF);
    //						Add(a[k][p] + r * c, a[i][j], INF);
                        }
        for (register int i = 1; i <= r; i++)
            for (register int j = 1; j <= c; j++)
                if (lizard[i][j] == 'L') Add(S, a[i][j], 1), ++n;
    }
    inline void bfs_(int s) {
        memset(dep, 0xff, sizeof(dep));
        dep[s] = 0;
        cnt[0] = 1;
        queue<int> q;
        q.push(s);
        while (!q.empty()) {
            int p = q.front();
            q.pop();
            for (register int i = first[p]; i >= 2; i = nxt[i]) {
                int v = to[i];
                if (dep[v] == -1) {
                    ++cnt[dep[v] = dep[p] + 1];
                    q.push(v);
                }
            }
        }
    }
    
    int max_flow;
    
    int dfs_(int p, int f) {
        if (p == T) {
            max_flow += f;
            return f;
        }
        int u = 0;
        for (register int i = first[p]; i >= 2; i = nxt[i]) {
            int v = to[i];
            if (flow[i] && dep[v] == dep[p] - 1) {
                int uu = dfs_(v, min(flow[i], f - u)); 
                if (uu) {
                    flow[i] -= uu;
                    flow[i ^ 1] += uu;
                    u += uu;
                }
                if (u >= f) {
                    return u;
                }
            }
        }
        if (!--cnt[dep[p]]) {
            dep[S] = r * c * 2 + 10;
        }
        ++cnt[++dep[p]];
        return u;
    }
    signed main() {
        r = read(); c = read(); d = read();
        build();
        bfs_(T);
        while (dep[S] < 2 * r * c + 9) dfs_(S, INF);
        printf("%lld", n - max_flow);
        return 0;
    }
    
  • 相关阅读:
    电脑不能连接到热点
    常用网络协议
    HVV面试
    【转载】hacker术语
    渗透测试学习路线
    系统安全——可信计算
    rsync文件同步详解
    rabbitmq集群部署高可用配置
    ansible自动化部署之路笔记
    ELK-elasticsearch-6.3.2部署
  • 原文地址:https://www.cnblogs.com/kma093/p/11216400.html
Copyright © 2011-2022 走看看