您的位置:首页 > 其它

ZOJ 1516 二分匹配

2013-09-05 21:37 253 查看
题意:给你n*m的土地,有k个1*1的方块被挖掉, 现在你要卖剩下的地(<=50),地只能是1*2 或2*1卖,问你最多能卖几块。

思路:剩下的点按奇偶分成两列点阵(i+j为奇数就是奇点,反之就是偶点)。二分匹配可解

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 55;
int n, m, k;
bool map[103][103];
int idx[103][103];
int id;
vector <int> edge[maxn];
int pre[maxn];
bool vis[maxn];
bool dfs(int u) {
for(int i = 0; i < (int) edge[u].size(); i++) {
int v = edge[u][i];
if(vis[v])
continue;
vis[v] = 1;
if(pre[v] == -1 || dfs(pre[v])) {
pre[v] = u;
return 1;
}
}
return 0;
}
int dir[4][2] = { -1, 0, 1, 0, 0, 1, 0, -1 };
int main() {
int i, j;
while(~scanf("%d%d", &n, &m) && n && m) {
scanf("%d", &k);
int x, y;
memset(map, 0, sizeof(map));
while(k--) {
scanf("%d%d", &x, &y);
x--; y--;
map[x][y] = 1;
}
id = 0;
for(i = 0; i < n; i++)
for(j = 0; j < m; j++)
if(!map[i][j])
idx[i][j] = id++;
for(i = 0; i < id; i++)
edge[i].clear();
for(i = 0; i < n; i++)
for(j = 0; j < m; j++)
if(!map[i][j] && (i + j & 1)) {
for(k = 0; k < 4; k++) {
int x = i + dir[k][0];
int y = j + dir[k][1];
if(x < 0 || x >= n || y < 0 || y >= m || map[x][y])
continue;
edge[idx[i][j]].push_back(idx[x][y]);
}
}
memset(pre, -1, sizeof(int) * id);
int cnt = 0;
for(i = 0; i < n; i++)
for(j = 0; j < m; j++)
if(!map[i][j] && (i + j & 1)) {
memset(vis, 0, sizeof(bool) * id);
if(dfs(idx[i][j])) cnt++;
}
printf("%d\n", cnt);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: