[BZOJ 4439] [swerc 2015] Landscaping

这里写图片描述

Solution :

比较经典的网络流构图了吧, 求一发最小割

Code:

#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>

using namespace std;
typedef long long LL;
inline void read(int &x){x=0;char c;while((c=getchar())<'0'||c>'9');for(x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<1)+(x<<3)+c-'0');}

const int inf = 0x3f3f3f3f ;
const int N = 2505 ;

struct edge
{
    int to, c, n;
}e[N * 8];
int head[N], tot = 1;
inline void addEdge(int x, int y, int c)
{
    e[++tot] = (edge) {y, c, head[x]}, head[x] = tot;
}

namespace Max_Flow
{
    int num[N], d[N], pa[N], cur[N];
    int n, m, A, B, S, T;

    void init_bfs()
    {
        static int que[N], l, r;

        for (int i = 1; i < T; ++i) d[i] = T;
        l = r = 0, d[que[++r] = T] = 0;

        while (l < r)
        {
            int u = que[++l];
            for (int p = head[u]; p; p = e[p].n) if (e[p ^ 1].c && d[e[p].to] > d[u] + 1)
                d[e[p].to] = d[u] + 1, que[++r] = e[p].to;
        }
    }

    int augment()
    {
        int ret = inf, x = T;
        while (x != S)
        {
            ret = min(ret, e[pa[x]].c);
            x = e[pa[x] ^ 1].to;
        }
        x = T;
        while (x != S)
        {
            e[pa[x]].c -= ret, e[pa[x] ^ 1].c += ret;
            x = e[pa[x] ^ 1].to;
        }
        return ret;
    }

    int Maxflow()
    {
        init_bfs();
        for (int i = 1; i <= T; ++i) ++num[d[i]];
        memcpy(cur, head, sizeof(int) * (T + 2));

        int ret = 0, x = S;

        while (d[S] < T)
        {
            if (x == T) ret += augment(), x = S;
            bool ok = 0;
            for (int p = cur[x]; p; p = e[p].n) if (e[p].c)
            {
                int to = e[p].to;
                if (d[to] + 1 == d[x]) { ok = 1, cur[x] = pa[to] = p, x = to; break ; }
            }
            if (!ok)
            {
                if (!(--num[d[x]])) break ;
                int mm = T + 1;
                for (int p = head[x]; p; p = e[p].n) if (e[p].c) mm = min(mm, d[e[p].to]);
                ++num[d[x] = mm + 1], cur[x] = head[x];
                if (x != S) x = e[pa[x] ^ 1].to;
            }
        } 

        return ret;
    }

    inline int id(int x, int y)
    {
        return (x - 1) * m + y;
    }

    void main()
    {
        static char ch[255];

        read(n), read(m), read(A), read(B);
        S = n * m + 1, T = S + 1;

        for (int i = 1; i <= n; ++i)
        {
            scanf("%s", ch + 1);
            for (int j = 1; j <= m; ++j)
            {
                int tmp = id(i, j);
                if (ch[j] == '#') 
                    addEdge(S, tmp, B), addEdge(tmp, S, 0);
                else 
                    addEdge(tmp, T, B), addEdge(T, tmp, 0);
                if (i > 1) 
                    addEdge(tmp, id(i - 1, j), A), addEdge(id(i - 1, j), tmp, A);
                if (j > 1)
                    addEdge(tmp, id(i, j - 1), A), addEdge(id(i, j - 1), tmp, A);
            }
        }

        printf("%d\n", Maxflow());
    }
}


int main()
{
    #ifdef LX_JUDGE
    freopen("in.txt", "r", stdin);
    #endif

    Max_Flow::main();

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值