【题目大意】

在网格图中放象棋里的车,只能放在'0'的空地上,'2'可阻断。要使放置的车两两不能相互攻击,求最大安置数及其方案。

传送门

【分析】

二分图最大匹配问题。

思考如何建图。

先简化问题,如果没有'2'可阻断这个条件的话,那么就应该对所有空地'0'的第i行连向第j列,然后跑最大匹配。

当有了'2'这个条件之后,我们可以发现,在同一行中,若两块空地中间有'2',那么它们都可以被选,类似地,对于竖列也是同样的道理,那么我们就可以把每个空地向右走的第一个'2'连向向下走的第一个'2',然后就可以开心地跑二分图最大匹配了。

【Code】

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int P = 19260817;
const int N = 200 + 5;
inline int read(){
    int f = 1, x = 0; char ch;
    do { ch = getchar(); if (ch == '-') f = -1; } while (ch < '0' || ch > '9');
    do {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); } while (ch >= '0' && ch <= '9');
    return f * x;
}
inline void hand_in() {
    freopen("guard.in", "r", stdin);
    freopen("guard.out", "w", stdout);
}
int m, n, mp[N][N];
struct Sakura {
    int to, nxt;
}sak[400005]; int head[400005], cnt;
inline void add(int x, int y) {
    ++cnt;
    sak[cnt].to = y, sak[cnt].nxt = head[x], head[x] = cnt;
}
inline int calc(int x, int y) {
    return (x - 1) * (m + 1) + y;
}
int match[400005], vis[400005], ans;
inline bool dfs(int u) {
    for (int i = head[u];i;i = sak[i].nxt) {
        int v = sak[i].to;
        if (!vis[v]) {
            vis[v] = 1;
            if (!match[v] || dfs(match[v])) {
                match[v] = u;
                return 1;
            }
        }
    }
    return 0;
}

inline pair <int, int> dis(int t) {
    int x = (t - 1) / (m + 1) + 1;
    int y = t - (x - 1) * (m + 1);
    return make_pair(x, y);
}

int main(){
//  hand_in();
    n = read(), m = read();
    for (int i = 1;i <= n; ++i) {
        for (int j = 1;j <= m; ++j) {
            mp[i][j] = read();
        }
    }
    for (int i = 0;i <= n + 1; ++i) mp[i][0] = mp[i][m + 1] = 2;
    for (int i = 0;i <= m + 1; ++i) mp[0][i] = mp[n + 1][i] = 2;

    for (int i = 1, x, y;i <= n; ++i) {
        for (int j = 1;j <= m; ++j) {
            if (!mp[i][j]) {
                x = i + 1, y = j + 1;
                while (mp[i][y] != 2) y ++;
                while (mp[x][j] != 2) x ++;
                add(calc(i, y), calc(x, j));
            }
        }
    }

    for (int i = 1;i <= n; ++i) {
        for (int j = 1;j <= m; ++j) {
            if (mp[i][j + 1] == 2) {
                memset(vis, 0, sizeof vis);
                if (dfs(calc(i, j + 1))) ++ans;
            }
        }
    }

    printf("%d\n", ans);

    for (int i = 1, t;i <= n; ++i) {
        for (int j = 1;j <= m; ++j) {
            t = calc(i + 1, j);
            if (match[t]) {
                printf("%d %d\n", dis(match[t]).first, j);
            }
        }
    }
    return 0;
}
01-14 03:05
查看更多