• bzoj1458 士兵占领


    Description

    有一个 (n)(m) 列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态。要求第 (i) 行第 (j) 列的格子只能参与 (m_{i,j})次交换。

    Input

    第一行包含两个整数 (n,m(1le n, mle 20)) 。以下 (n) 行为初始状态,每行为一个包含 (m) 个字符的 (01) 串,其中 (0) 表示黑色棋子, (1) 表示白色棋子。以下 (n) 行为目标状态,格式同初始状态。以下 (n) 行每行为一个包含 (m)(0) ~ (9) 数字的字符串,表示每个格子参与交换的次数上限。

    Output

    输出仅一行,为最小交换总次数。如果无解,输出 (-1)

    Sample Input

    3 3
    110
    000
    001
    000
    110
    100
    222
    222
    222

    Sample Output

    4

    Solution

    有趣的费用流题。

    非常显然,(S) 要连原图中的黑点,新图中的黑点要连 (T),关键是中间的边怎么搞。

    于是考虑拆点,最开始一拆二发现好像不可做。最后发现一拆三是可行的。

    (x) 拆成 (x_1,x_2,x_3)
    其中

    • (<x_1, x_2>)(x) 最多流入的流量
    • (<x_2, x_3>)(x) 最多流出的流量

    对于每个 (x) 在原图和新图中的情况,分类连边

    • 在原图中是黑点,在新图中是白点

      • (<x_1, x_2>:capacity=frac{use[x]}{2};cost=0)
      • (<x_2, x_3>:capacity=frac{use[x]+1}{2};cost=0)
    • 在原图中是白点,在新图中是黑点
      - (<x_1, x_2>:capacity=frac{use[x] + 1}{2};cost=0)
      - (<x_2, x_3>:capacity=frac{use[x]}{2};cost=0)

    • 在原图和新图中状态相同
      - (<x_1, x_2>:capacity=frac{use[x]}{2};cost=0)
      - (<x_2, x_3>:capacity=frac{use[x]}{2};cost=0)

    还有点之间的连边。对于连通的 (x,y)(<x_3,y_1>:capacity=INF;cost = 1)

    注意判断一下无解的情况就万事大吉了。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define N 10001
    #define INF 2000000000
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    
    char st[21][21], ed[21][21], use[21][21];
    int n, m, ans, flow;
    
    int S, T;
    struct edge { int u, v, c, w, next; }e[100001];
    int head[N], tot = 1;
    int q[N], dis[N], pre[N];
    bool inq[N];
    
    inline void insert(int u, int v, int c, int w) { e[++tot].u = u, e[tot].v = v, e[tot].c = c, e[tot].w = w, e[tot].next = head[u], head[u] = tot; }
    inline void add(int u, int v, int c, int w) { insert(u, v, c, w), insert(v, u, 0, -w); }
    
    inline bool spfa() {
        rep(i, S, T) dis[i] = INF; dis[S] = 0;
        int l = 1, r = 1; q[1] = S;
        while (l <= r) {
            int u = q[l++]; inq[u] = 0;
            for (int i = head[u], v, w; i; i = e[i].next) {
                if (e[i].c > 0 && dis[v = e[i].v] > dis[u] + (w = e[i].w)) {
                    dis[v] = dis[u] + w, pre[v] = i;
                    if (!inq[v]) q[++r] = v, inq[v] = 1;
                }
            }
        }
        return dis[T] != INF;
    }
    
    inline void mcf() {
        int d = INF;
        for (int i = T; i != S; i = e[pre[i]].u) d = min(d, e[pre[i]].c);
        flow += d;
        for (int i = T; i != S; i = e[pre[i]].u) e[pre[i]].c -= d, e[pre[i] ^ 1].c += d, ans += d * e[pre[i]].w;
    }
    
    int main() {
        cin >> n >> m; T = n * m * 3 + 1;
        rep(i, 1, n) scanf("%s", st[i] + 1);
        rep(i, 1, n) scanf("%s", ed[i] + 1);
        rep(i, 1, n) scanf("%s", use[i] + 1);
        int black = 0, white = 0;
        rep(i, 1, n) rep(j, 1, m) {
            int x1 = (i - 1) * m + j, x2 = x1 + n * m, x3 = x2 + n * m, Use = use[i][j] - '0';
            if (st[i][j] == '1' && ed[i][j] == '0')
                black++, add(S, x2, 1, 0), add(x1, x2, Use / 2, 0), add(x2, x3, (Use + 1) / 2, 0);
            else if (st[i][j] == '0' && ed[i][j] == '1')
                white++, add(x2, T, 1, 0), add(x1, x2, (Use + 1) / 2, 0), add(x2, x3, Use / 2, 0);
            else
                add(x1, x2, Use / 2, 0), add(x2, x3, Use / 2, 0);
            if ((i ^ 1) && (j ^ 1)) add(x3, (i - 2) * m + j - 1, INF, 1);
            if (i ^ 1) add(x3, (i - 2) * m + j, INF, 1);
            if ((i ^ 1) && (j ^ m)) add(x3, (i - 2) * m + j + 1, INF, 1);
            if (j ^ 1) add(x3, (i - 1) * m + j - 1, INF, 1);
            if (j ^ m) add(x3, (i - 1) * m + j + 1, INF, 1);
            if ((i ^ n) && (j ^ 1)) add(x3, i * m + j - 1, INF, 1);
            if (i ^ n) add(x3, i * m + j, INF, 1);
            if ((i ^ n) && (j ^ m)) add(x3, i * m + j + 1, INF, 1);
        }
        if (black ^ white) { puts("-1"); return 0; }
        while (spfa()) mcf();
        cout << (flow == black ? ans : -1);
        return 0;
    }
    
  • 相关阅读:
    滚动菜单BUG修复
    前端之滚动菜单
    数据仓库操作
    mysql之分页与慢日志以及表知识补充
    mysql之索引
    mysql之内置函数
    mysql之触发器与事务
    pymysql操作数据库之存储过程
    复习mysql语句
    经典mysql测试题
  • 原文地址:https://www.cnblogs.com/aziint/p/8416473.html
Copyright © 2020-2023  润新知