HDU 4185 - Oil Skimming ( 二分图匹配, 匈牙利算法 )
题意
给出一个 n * n的油田,现在要撇去一些油,但是每次只能撇掉1 * 2或者2 *1的油,问最多能撇多少次。
思路
匹配
建图:给每个“#”标序号后,dfs找每个油田位置的上下左右是否有油田,若有则建边。跑匈牙利匹配即可。
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 600+5;
int turn[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
char s[maxn][maxn];
int num[maxn][maxn];
int g[maxn][maxn];
int match[maxn];
bool used[maxn];
int n, k;
int number;
bool dfs(int v)
{
for(int j = 1; j <= number; j++){
if(g[v][j] && !used[j]){
used[j] = 1;
if(match[j] == 0 || dfs(match[j]) == 1){
match[j] = v;
return true;
}
}
}
return false;
}
int hungary()
{
int res = 0;
memset(match, 0, sizeof match);
for(int v = 1; v <= number; v++){
memset(used, 0, sizeof used);
if(dfs(v)) res++;
}
return res;
}
int main()
{
int T;
scanf("%d",&T);
for(int kase = 1; kase <= T; kase++){
scanf("%d",&n);
memset(num, 0, sizeof num);
memset(g, 0, sizeof g);
number = 0;
for(int i = 0; i < n; i++){
scanf("%s",&s[i]);
for(int j = 0; j < n; j++){
if( s[i][j] == '#' ){
num[i][j] = ++number;
}
}
}
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if( s[i][j] == '#' ){
for(int k = 0; k < 4; k++){
int x = i + turn[k][0], y = j + turn[k][1];
if( x >= 0 && x < n && y >= 0 && y < n && s[x][y] == '#' ){
int n1 = num[i][j], n2 = num[x][y];
g[n1][n2] = 1;
}
}
}
}
}
int ans = hungary();
printf("Case %d: %d\n",kase,ans/2);
}
return 0;
}