Maze 第二十届浙大城市学院程序设计竞赛 (二分图,网络流(对于表格,矩阵是如何建边的))

发布时间 2023-04-04 09:31:48作者: VxiaohuanV

题目大意:

  • 给出一个01矩阵, 给出q,p 分别表示 选一个点的权值,和选2个连在一起的点的权值
  • 问如何让权值更大

 

注意 : 在Dinic 的时间复杂度对于二分图这种边权为1, 时间复杂度为 NsqrtN,  不是n^2 m  

思路:

  • 更具题目的条件限制,他的建边一定是2个矮在一起的
  • 因此更具 (i+j)%2, 连转换成二分图, (在一边的2个点一定不会建边)
  • 然后网络流Dinic跑二分图匹配即可
#include <bits/stdc++.h>
using namespace std;
const int N = 310;
const int V = N * N, E = V << 2;
template <class T>
struct FlowGraph {
    int s, t, totv, idx, head[V], dis[V], cur[V];
    struct edge {
        int v, nxt;
        T f;
    } e[E << 1];
    void addedge(int u, int v, T f) {
        //有向边反边权值为0,无向边为f
        e[idx] = {v, head[u], f}; head[u] = idx++;
        e[idx] = {u, head[v], 0}; head[v] = idx++;
    } 
    int bfs() {
        for (int i = 1; i <= totv; i++) {
            dis[i] = 0;
            cur[i] = head[i];
        }
        dis[s] = 1;
        queue<int> q;
        q.push(s);
        while (q.size()) {
            int sz = q.size();
            while (sz--) {
                int u = q.front(); q.pop();
                for (int i = head[u]; ~i; i = e[i].nxt) {
                    if (e[i].f && !dis[e[i].v]) {
                        int v = e[i].v;
                        dis[v] = dis[u] + 1;
                        if (v == t) return 1;
                        q.push(v);
                    }
                }
            }
        }
        return 0;
    }
    T dfs(int u, T rem) {
        if (u == t) return rem;
        T flow = 0;
        for (int i = cur[u]; ~i; cur[u] = i = e[i].nxt) {
            if (e[i].f && dis[e[i].v] == dis[u] + 1) {
                int v = e[i].v;
                T f = dfs(v, min(rem, e[i].f));
                e[i].f -= f;
                e[i ^ 1].f += f;
                rem -= f;
                flow += f;
                if (!rem) break;
            }
        }
        if (!flow) dis[u] = -1;
        return flow;
    }
    T dinic() {
        T flow = 0;
        while (bfs()) flow += dfs(s, 0x3f3f3f3f);
        return flow;
    }
    void init(int _s, int _t, int _totv) {
        s = _s;
        t = _t;
        totv = _totv;
        idx = 0;
        for (int i = 1; i <= totv; i++) head[i] = -1;
    }
};
FlowGraph<int> g;
int n, m, p, q, vis[N][N], id[N][N], col[N * N];
char s[N][N];
long long ans;
pair<int, int> path[E];
void solve(int sx, int sy) {
    int cnt = 0, idx = 0;
    auto get = [&](int x, int y) {
        if (id[x][y] == 0) {
            id[x][y] = ++idx;
            col[idx] = (x + y) & 1;
        }
        return id[x][y];
    };
    get(sx, sy);
    auto add = [&](int x, int y) {
        if (col[x] == 0) g.addedge(x, y, 1);
    };
    function <void(int, int)> dfs = [&](int x, int y) {
        vis[x][y] = 1;
        if (x + 1 <= n && s[x + 1][y] == '1') {
            if (!vis[x + 1][y]) dfs(x + 1, y);
            path[++cnt] = {get(x, y), get(x + 1, y)};
        } 
        if (y + 1 <= m && s[x][y + 1] == '1') {
             if (!vis[x][y + 1]) dfs(x, y + 1);
            path[++cnt] = {get(x, y), get(x, y + 1)};
        }
        if (y - 1 >= 1 && s[x][y - 1] == '1') {
             if (!vis[x][y - 1]) dfs(x, y - 1);
            path[++cnt] = {get(x, y), get(x, y - 1)};   
        }
        if (x - 1 >= 1 && s[x - 1][y] == '1') {
            if (!vis[x - 1][y]) dfs(x - 1, y);
            path[++cnt] = {get(x, y), get(x - 1, y)};
        }
    };
    dfs(sx, sy);
    int S = idx + 1, T = idx + 2;
    g.init(S, T, T);;
    for (int i = 1; i <= cnt; i++) add(path[i].first, path[i].second);
    for (int i = 1; i <= idx; i++) {
        if (col[i] == 0) {
            g.addedge(S, i, 1);
        } else {
            g.addedge(i, T, 1);
        }
    }
    int maxV = g.dinic();
    ans += max(1ll * maxV * q + 1ll * (idx - maxV * 2) * p, 1ll * idx * p);
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m >> p >> q;
    for (int i = 1; i <= n; i++) {
        cin >> (s[i] + 1);
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (!vis[i][j] && s[i][j] == '1') {
                solve(i, j);
            }
        }
    }
    cout << ans;
    return 0;
}
偷的代码