Luogu P1263 宫廷守卫
这守卫怕不是铁憨憨,互相\(TK\)欢乐多
如果没有墙的话,可以将它的行和列分别看成点,对于每一块空地\((i, j)\),在\(i\)、\(j\)之间连一条边,然后跑二分图匹配就好了
然后考虑墙的影响,墙会把一行或一列分成几段互不影响的区间,将这几段区间的行(列)标上不同号,表示它们互不影响,然后再跑二分图匹配就好了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
LL read() {
LL k = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
k = k * 10 + c - 48, c = getchar();
return k * f;
}
int mapp[210][210];
struct zzz {
int t, nex;
}e[40010 << 2]; int head[40010], tot;
void add(int x, int y) {
e[++tot].t = y;
e[tot].nex = head[x];
head[x] = tot;
}
int pos[210][210], pos2[210][210], cnt, cnt2;
bool vis[40010]; int lin[40010];
bool findd(int x) {
for(int i = head[x]; i; i = e[i].nex)
if(!vis[e[i].t]) {
vis[e[i].t] = 1;
if(!lin[e[i].t] || findd(lin[e[i].t])) {
lin[e[i].t] = x; return 1;
}
}
return 0;
}
int main() {
int n = read(), m = read();
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
mapp[i][j] = read();
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(mapp[i][j] != 2)
if(mapp[i][j-1] == 2 || !(j-1)) pos[i][j] = ++cnt;
else pos[i][j] = pos[i][j-1];
for(int j = 1; j <= m; ++j)
for(int i = 1; i <= n; ++i)
if(mapp[i][j] != 2)
if(mapp[i-1][j] == 2 || !(i-1)) pos2[i][j] = ++cnt2;
else pos2[i][j] = pos2[i-1][j];
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(mapp[i][j] == 0) add(pos[i][j], pos2[i][j]);
int ans = 0;
for(int i = 1; i <= cnt; ++i) {
for(int j = 1; j <= cnt2; ++j) vis[j] = 0;
ans += findd(i);
}
printf("%d\n", ans);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j) {
if(!mapp[i][j] && pos[i][j] == lin[pos2[i][j]]) printf("%d %d\n", i, j);
}
return 0;
}