Uncle Tom’s Inherited Land
题意
给定一个
n
×
m
n \times m
n×m 的网格图,其中若干个格子成了池塘,其他格子可以贩卖(池塘不可贩卖),但是贩卖规格只能是以
1
×
2
1 \times 2
1×2 的长方形形状贩卖,如上图
问最多能贩卖多少个
1
×
2
1 \times 2
1×2 的长方形?
思路
我们不妨将贩卖关系建模成两个小格子之间的连边,现在问题就转化成了:如果选择最多的边?且任意两边没有共享同一个节点
这样就可以用二分图匹配来解决,问题是如何区分左点和右点
我们可以以
i
+
j
i + j
i+j 的奇偶性来区分左点和右点,因为相邻的两点到左上角的奇偶性肯定不同
这样子就可以在二分图上跑最大匹配了。
其实也可以不区分左点和右点,只需要将所有边连成双向边,然后照例跑二分图最大匹配,等价于将原图复制了一遍,最大匹配数量也会加倍,除 2 2 2 即可
// Problem: Uncle Tom's Inherited Land*
// Contest: HDOJ
// URL: https://acm.hdu.edu.cn/showproblem.php?pid=1507
// Memory Limit: 65 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
#define fore(i,l,r) for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
const int INF=0x3f3f3f3f;
const long long INFLL=0x3f3f3f3f3f3f3f3fLL;
typedef long long ll;
std::vector<std::vector<int>> g;
std::vector<int> match;
std::vector<bool> used;
const int N = 105;
int a[N][N];
int mv[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
bool dfs(int u){
for(auto v : g[u])
if(!used[v]){
used[v] = true;
if(match[v] == -1 || dfs(match[v])){
match[v] = u;
return true;
}
}
return false;
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int n, m;
while(std::cin >> n >> m && n && m){
fore(i, 0, n)
fore(j, 0, m)
a[i][j] = 0;
int k;
std::cin >> k;
while(k--){
int x, y;
std::cin >> x >> y;
--x;
--y;
a[x][y] = 1;
}
auto in = [&](int x, int y) -> bool {
return x >= 0 && x < n && y >= 0 && y < m;
};
int up = n * m + 5;
g.assign(up, std::vector<int>());
match.assign(up, -1);
fore(x, 0, n)
fore(y, 0, m){
if(a[x][y]) continue;
for(auto [dx, dy] : mv){
int nx = x + dx, ny = y + dy;
if(in(nx, ny) && !a[nx][ny]){
if((x + y) & 1) //奇点 -> 偶点
g[x * m + y].push_back(nx * m + ny);
else
g[nx * m + ny].push_back(x * m + y);
}
}
}
int cnt = 0;
fore(i, 0, up){
used.assign(up, false);
cnt += dfs(i);
}
std::cout << cnt << endl;
std::set<std::pair<int, int>> vis;
fore(i, 0, up){
if(match[i] == -1) continue;
int u = match[i];
std::pair<int, int> p1 = {u / m, u % m};
std::pair<int, int> p2 = {i / m, i % m};
std::cout << "(" << p1.fi + 1 << "," << p1.se + 1 << ")--(" <<
p2.fi + 1 << "," << p2.se + 1 << ")" << endl;
}
std::cout << endl;
}
return 0;
}