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;
}
posted @ 2018-08-22 21:16  JinxiSui  阅读(115)  评论(0编辑  收藏  举报