zoukankan      html  css  js  c++  java
  • 【二分图最大点独立集/最小割】P2774 方格取数问题

    P2774 方格取数问题

    思路

    骑士共存问题类似。同样将顶点分为奇数点和偶数点,则可以全部只取奇数点,或全部只取偶数点;若取了一个奇数点((i,j)),则受影响的只有一部分偶数点,即无法取得的与其有公共边的顶点((i-1,j),(i+1,j),(i,j-1),(i,j+1)),而所有奇数点都不受影响;偶数点同理。

    由此可以抽象成二分图模型,奇数点为左部点,偶数点为右部点,在互相影响的顶点间连一条有向边。注意必须从右部点出发,连向左部点。如果反过来连会WA(为什么?)。然后问题即求二分图最大独立集=总点权-最大匹配(最小割).

    写错一堆细节……

    • 坐标哈希,应该是((x-1)*m+y),不是(x*n+y),也不是((x-1)*n+y)!!
    • 判断点是奇数点还是偶数点,是用(i+j)&1,不是solve(i,j)&1!!
    • 顶点内部连边,只能在连向了汇点的顶点里遍历,不能在被源点连向的顶点里遍历,前者AC,后者全部WA(为什么?)

    代码

    const int INF = 0x3f3f3f3f;
    const int maxn = 6e2 + 100;
    const int maxm = 2e4 + 100;
    int cnt_e = 1;
    int head[maxn];
    int n, m;
    int s, t;
    int cur[maxn], depth[maxn], gap[maxn];
    LL Maxflow = 0;
    
    struct Edge {
        int from, to, next;
        LL w;
    }e[maxm];
    void addn(int& cnt_e, int head[], Edge e[], int u, int v, LL w) {
        //网络流建图
        e[++cnt_e].next = head[u]; e[cnt_e].from = u; e[cnt_e].to = v; e[cnt_e].w = w; head[u] = cnt_e;
        e[++cnt_e].next = head[v]; e[cnt_e].from = v; e[cnt_e].to = u; e[cnt_e].w = 0; head[v] = cnt_e;
    }
    
    void bfs() {
        mem(depth, -1);
        mem(gap, 0);
        depth[t] = 0;
        gap[0] = 1;
        cur[t] = head[t];
        queue<int> q;
        q.push(t);
        while (q.size()) {
            int u = q.front(); q.pop();
            for (int i = head[u]; i; i = e[i].next) {
                int v = e[i].to;
                if (depth[v] != -1) continue;
                q.push(v);
                depth[v] = depth[u] + 1;
                gap[depth[v]]++;
            }
        }
        return;
    }
    
    LL dfs(int now, LL minflow,int n) {
        if (now == t) {
            Maxflow += minflow;
            return minflow;
        }
        LL nowflow = 0;
        for (int i = cur[now]; i; i = e[i].next) {
            cur[now] = i;
            int v = e[i].to;
            if (e[i].w && depth[v] + 1 == depth[now]) {
                LL k = dfs(v, min(e[i].w, minflow - nowflow), n);
                if (k) {
                    e[i].w -= k;
                    e[i ^ 1].w += k;
                    nowflow += k;
                }
                if (minflow == nowflow) return nowflow;
            }
        }
        gap[depth[now]]--;
        if (!gap[depth[now]]) depth[s] = n + 1;
        depth[now]++;
        gap[depth[now]]++;
        return nowflow;
    }
    
    LL ISAP(int n) {
        Maxflow = 0;
        bfs();
        while (depth[s] < n) {
            memcpy(cur, head, sizeof(head));
            dfs(s, INF, n);
        }
        return Maxflow;
    }
    
    int solve(int x, int y) {
        return (x - 1) * m + y;
    }
    
    int dirx[] = { 0,0,1,-1 };
    int diry[] = { 1,-1,0,0 };
    
    int main() {
        ios::sync_with_stdio(false);
        cin >> n >> m;
        s = n * m + 1;
        t = s + 1;
        LL sum = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                LL val; cin >> val;
                sum += val;
                if ((i + j) & 1) {
                    addn(cnt_e, head, e, s, solve(i, j), val);
                }
                else {
                    addn(cnt_e, head, e, solve(i, j), t, val);
                    for (int k = 0; k < 4; k++) {
                        int nx = i + dirx[k];
                        int ny = j + diry[k];
                        if (nx<1 || ny<1 || nx>n || ny>m) continue;
                        addn(cnt_e, head, e, solve(i, j), solve(nx, ny), INF);
                    }
                }
            }
        }
        ISAP(n * m + 2);
        cout << sum - Maxflow;
        
        return 0;
    }
    
  • 相关阅读:
    KNN算法
    mysql必须知道的
    励志的演讲
    30条程序员名言警句
    别人的文章:为什么软件开发,人多,事少,还会工作量大?
    分享一个比较受启发的文章“学历代表过去,能力代表现在,学习力代表未来”
    mvc 学前必知
    启动docker容器 防火墙问题报错 ! -i docker0' failed: iptables: No chain/target/match by that name.
    git指令详解总结
    git reset 版本回退的三种用法总结
  • 原文地址:https://www.cnblogs.com/streamazure/p/14150453.html
Copyright © 2011-2022 走看看