zoukankan      html  css  js  c++  java
  • BZOJ 2668 [cqoi2012]交换棋子 | 最小费用最大流

    传送门

    BZOJ 2668

    题解

    同时分别限制流入和流出次数,所以把一个点拆成三个:入点in(x)、中间点mi(x)、出点ou(x)。

    如果一个格子x在初始状态是黑点,则连(S, mi(x), 1, 0)
    如果x在目标状态是黑点,则连(mi(x), T, 1, 0)
    设x的交换次数限制是w
    如果x在两种状态中颜色相同,则连(in(x), mi(x), w / 2, 0), (mi(x), ou(x), w / 2, 0)
    如果x只在初始状态为黑色,则连(in(x), mi(x), w / 2, 0), (mi(x), ou(x), (w + 1) / 2, 0)
    如果x只在目标状态为黑色,则连(in(x), mi(x), (w + 1) / 2, 0), (mi(x), ou(x), w / 2, 0)
    每个点x和相邻的点y(八连通),连(ou(x), in(y), INF, 1)

    然后最小费用最大流即可。

    #include <queue>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #define space putchar(' ')
    #define enter putchar('
    ')
    typedef long long ll;
    using namespace std;
    template <class T>
    void read(T &x){
        char c;
        bool op = 0;
        while(c = getchar(), c < '0' || c > '9')
            if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
            x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    
    const int N = 1234, M = 1000005, INF = 0x3f3f3f3f;
    const int dx[] = {-1, 1, 0, 0, -1, -1, 1, 1};
    const int dy[] = {0, 0, -1, 1, -1, 1, -1, 1};
    int n, m, tot, maxflow, mincost, src = 1, des = 2, id[23][23][3], b1, b2;
    int ecnt = 1, adj[N], pre[N], dis[N], nxt[M], go[M], cap[M], cost[M];
    char st[23][23], ed[23][23], cp[23][23];
    
    void _add(int u, int v, int w, int c){
        go[++ecnt] = v;
        nxt[ecnt] = adj[u];
        adj[u] = ecnt;
        cap[ecnt] = w;
        cost[ecnt] = c;
    }
    void add(int u, int v, int w, int c){
        _add(u, v, w, c);
        _add(v, u, 0, -c);
    }
    bool spfa(){
        queue <int> que;
        static bool inq[N] = {0};
        for(int i = 1; i <= tot; i++)
            dis[i] = INF, pre[i] = 0;
        dis[src] = 0, que.push(src), inq[src] = 1;
        while(!que.empty()){
            int u = que.front();
            que.pop(), inq[u] = 0;
            for(int e = adj[u], v; e; e = nxt[e]){
                if(cap[e] && dis[u] + cost[e] < dis[v = go[e]]){
                    dis[v] = dis[u] + cost[e], pre[v] = e;
                    if(!inq[v]) que.push(v), inq[v] = 1;
                }
            }
        }
        return dis[des] < INF;
    }
    void mcmf(){
        while(spfa()){
            int delta = INF;
            for(int e = pre[des]; e; e = pre[go[e ^ 1]])
                delta = min(delta, cap[e]);
            for(int e = pre[des]; e; e = pre[go[e ^ 1]])
                cap[e] -= delta, cap[e ^ 1] += delta;
            maxflow += delta;
            mincost += delta * dis[des];
        }
    }
    bool legal(int x, int y){
        return x > 0 && y > 0 && x <= n && y <= m;
    }
    
    int main(){
    
        read(n), read(m), tot = 3 * n * m + 2;
        for(int i = 1, cnt = 2; i <= n; i++)
            for(int j = 1; j <= m; j++)
                id[i][j][0] = ++cnt, id[i][j][1] = ++cnt, id[i][j][2] = ++cnt;
        for(int i = 1; i <= n; i++) scanf("%s", st[i] + 1);
        for(int i = 1; i <= n; i++) scanf("%s", ed[i] + 1);
        for(int i = 1; i <= n; i++) scanf("%s", cp[i] + 1);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++){
                int w = cp[i][j] - '0';
                if(st[i][j] == '1') b1++, add(src, id[i][j][0], 1, 0);
                if(ed[i][j] == '1') b2++, add(id[i][j][0], des, 1, 0);
                if(st[i][j] == ed[i][j]){
                    add(id[i][j][1], id[i][j][0], w / 2, 0);
                    add(id[i][j][0], id[i][j][2], w / 2, 0);
                }
                else if(st[i][j] == '1'){
                    add(id[i][j][1], id[i][j][0], w / 2, 0);
                    add(id[i][j][0], id[i][j][2], (w + 1) / 2, 0);
                }
                else if(ed[i][j] == '1'){
                    add(id[i][j][1], id[i][j][0], (w + 1) / 2, 0);
                    add(id[i][j][0], id[i][j][2], w / 2, 0);
                }
                for(int d = 0, x, y; d < 8; d++)
                    if(legal(x = i + dx[d], y = j + dy[d]))
                        add(id[i][j][2], id[x][y][1], INF, 1);
            }
        mcmf();
        if(maxflow < max(b1, b2)) puts("-1");
        else write(mincost), enter;
        
        return 0;
    }
    
  • 相关阅读:
    废水回收
    XJOI网上同步训练DAY6 T2
    XJOI网上同步训练DAY6 T1
    Codeforces 351B Jeff and Furik
    对拍 For Linux
    Codeforces 432D Prefixes and Suffixes
    Codeforces 479E Riding in a Lift
    Codeforces 455B A Lot of Games
    Codeforces 148D Bag of mice
    Codeforces 219D Choosing Capital for Treeland
  • 原文地址:https://www.cnblogs.com/RabbitHu/p/BZOJ2668.html
Copyright © 2011-2022 走看看