zoukankan      html  css  js  c++  java
  • BZOJ 1001: [BeiJing2006]狼抓兔子 (最小割)

    虽然联赛考崩了,但还是要继续坚持下去啊,以后就去BZOJ上刷题吧QwQ

    题目大意

    给你一个(n*m)的矩形平面图,斜边和直边上都有权值,选一些边,使((1,1))((n,m))分开,使这些边权值和最小!

    解题思路

    比较明显的一个最小割,和[ZJOI2009]狼和羊的故事很像的,都是将两个联通块分开,问分开边权和的最小值。

    一开始调了比较久,答案都小了,因为我没有将从下向上走的边连上去,这种就会使答案偏小,所以以后要多注意一下这种最小割的题要连两条边。

    而且这种题目好像也不用拆点。。所以一开始有点傻,拆了点做的所以(GetPoint)会多一个(id)自动忽略掉吧。。

    好像最小割并不是正解,但进行一些优化能卡过去(参考了下hzwer大佬的)。

    正解使S-T平面图上求最小割,具体参考这篇论文

    像那种双向边,可以都连边权值大小的边,没必要连反向边了(因为可以把它们当做互为反向边)。

    代码

    /**************************************************************
        Problem: 1001
        User: zjp_shadow
        Language: C++
        Result: Accepted
        Time:1512 ms
        Memory:84972 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    #define For(i, l, r) for(register int i = (l), _end_ = (int)(r); i <= _end_; ++i)
    #define Fordown(i, r, l) for(register int i = (r), _end_ = (int)(l); i >= _end_; --i)
    #define Set(a, v) memset(a, v, sizeof(a))
    using namespace std;
     
    bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
    bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
     
    inline int read() {
        int x = 0, fh = 1; char ch = getchar();
        for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
        for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ '0');
        return x * fh;
    }
     
    void File() {
    #ifdef zjp_shadow
        freopen ("1001.in", "r", stdin);
        freopen ("1001.out", "w", stdout);
    #endif
    }
     
    const int N = 1010 * 1010, M = N * 6;
     
    int to[M], Next[M], Head[N], cap[M], e = 1;
    inline void add_edge (int u, int v, int w) {
        to[++e] = v;
        Next[e] = Head[u];
        cap[e] = w;
        Head[u] = e;
    }
     
    int S, T;
    int r, c;
    const int inf = 0x3f3f3f3f;
     
    inline int Get_Point(int x, int y, int id) { return (x - 1) * c + y; }
     
    int dis[N], n;
    inline bool Bfs() {
        Set(dis, 0);
        queue<int> Q;
        Q.push(S);
        dis[S] = 1;
        while (!Q.empty() ) {
            register int u = Q.front(); Q.pop();
            for (register int i = Head[u]; i; i = Next[i]) 
                if (!dis[to[i]] && cap[i]) {
                    register int v = to[i];
                    dis[v] = dis[u] + 1;
                    if (v == T) return true;
                    Q.push(v);
                }
        }
        return false;
    }
     
    int cur[N];
     
    int Dfs(int u, int max_flow) {
        if (u == T || !max_flow) return max_flow;
        register int flow = 0, f;
        for (register int& i = cur[u]; i; i = Next[i]) {
            if ((dis[u] + 1 == dis[to[i]]) && (f = Dfs(to[i], min(max_flow, cap[i]) ) ) ) {
                cap[i] -= f;
                cap[i ^ 1] += f;
                flow += f;
                max_flow -= f;
                if (!max_flow) break ;
            }
        }
        if (!flow) dis[u] = 0;
        return flow;
    }
     
    inline int Dinic() {
        int sum_flow = 0;
        while (Bfs() ) {
            For (i, 1, n)
                cur[i] = Head[i];
            sum_flow += Dfs(S, inf);
        }
        return sum_flow;
    }
     
    int main () {
        File() ;
        r = read(), c = read();
     
        For (i, 1, r)
            For (j, 1, c - 1) {
                static int u, v, w;
                u = Get_Point(i, j, 1);
                v = Get_Point(i, j + 1, 0);
                w = read() ;
                add_edge (u, v, w);
                add_edge (v, u, w);
            }
     
        For (i, 1, r - 1)
            For (j, 1, c) {
                static int u, v, w;
                u = Get_Point(i, j, 1);
                v = Get_Point(i + 1, j, 0);
                w = read() ;
                add_edge (u, v, w);
                add_edge (v, u, w);
            }
     
        For (i, 1, r - 1)
            For (j, 1, c - 1) {
                static int u, v, w;
                u = Get_Point(i, j, 1);
                v = Get_Point(i + 1, j + 1, 0);
                w = read() ;
                add_edge (u, v, w);
                add_edge (v, u, w);
            }
     
        S = Get_Point(1, 1, 0);
        T = Get_Point(r, c, 1);
        n = T;
        printf ("%d
    ", Dinic() ) ;
        return 0;
    }
    
  • 相关阅读:
    Centos-706停用firewalld启用Iptables服务
    apache访问日志分析[转]
    apache日志管理【转】
    [转]如何使用PHP实现javascript的escape和unescape函数
    [转]linux下centos服务器安全设置
    [转]sysctl -P 报错解决办法
    [转]解决error: "net.ipv4.netfilter.ip_conntrack_max" is an unknown key错误
    [转]CentOS Apache 性能调试!
    [转]怎么查看和修改 MySQL 的最大连接数?
    [转]同一台Windows机器中启动多个Memcached服务
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/7844257.html
Copyright © 2011-2022 走看看