http://wikioi.com/problem/1022/
一道二分图匹配,关键在于怎么建边,由题覆盖的为2个相连的陆地,我们可以看作是一块陆地和另一块陆地进行了匹配
于是就可以找到一个陆地,把这和四周的陆地进行加边,接下来就是匹配了
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;const int maxn = 40000+100 ;
int n , m , K ;
int tot , clock_vis, res = 1;
int head[maxn];
int vis[maxn];
int lin[maxn];
int dx[] = {0 , 0 , -1 , 1} ;
int dy[] = {1 , -1 , 0 , 0} ;
struct node{
int next,v;
}e[maxn] ;
void add(int u,int v) {
e[tot].v = v ;
e[tot].next = head[u] ;
head[u] = tot++ ;
}
bool find(int u) {
for(int i = head[u] ; i != -1 ; i = e[i].next) {
int v = e[i].v ;
if(vis[v] == clock_vis) continue ;
vis[v] = clock_vis ;//时间标记
if(!lin[v] || find(lin[v])) {
lin[v] = u ;
return true ;
}
}
return false ;
}
int main() {
scanf("%d%d%d",&n,&m,&K) ;
int x1 , y1 ;
for(int i = 0 ; i < K ; i++) {
scanf("%d%d",&x1,&y1) ;
x1-- ;
y1-- ;
vis[x1*m+y1] = -1 ;//一维保存坐标
}
for(int i = 0 ; i < n ; i++) {
for(int j = (i%2) ; j < m ; j+=2) if(vis[i*m+j] != -1){
head[res] = -1;
for(int k = 0 ; k <=3 ; k++) {
int nx = i + dx[k] ;
int ny = j + dy[k] ;
if(nx < 0 || ny < 0 || nx >= n || ny >= m) continue ;
if(vis[nx*m+ny] == -1) continue ;
add(res, nx*m+ny) ;//加边
}
res++ ;//记录陆地数
}
}
int ans = 0 ;
for(int i = 1 ; i < res ; i++){//二分匹配
clock_vis= i ;
if(find(i)) ans++ ;
}
printf("%d",ans) ;
return 0 ;
}