hdu 5093 Battle ships 二分图匹配

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5093

 

一开始就往贪心的方向想了结果wa全场

 

这种矩阵形式的图一般要联想到行和列构成了二分图

然后实质就是求一个最大匹配

中间的冰山实际上就是把一行或一列切成多个顶点而已

所以一开始预处理一下 然后就可以套用模板

 

#include <cstring>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <stack>
#include <vector>
#include <queue>
#include <map>

using namespace std;

const int maxn = 60;
const int maxv = 4000;
char a[maxn][maxn];

int V;
vector<int> G[maxv];
int match[maxv];
bool used[maxv];

void addedge(int u, int v)
{
    G[u].push_back(v);
    G[v].push_back(u);
}

bool dfs(int v)
{
    used[v] = true;
    for(int i = 0; i < G[v].size(); i++)
    {
        int u = G[v][i], w = match[u];
        if(w < 0 || !used[w] && dfs (w))
        {
            match[v] = u;
            match[u] = v;
            return true;
        }
    }
    return false;
}

int bipartite_matching()
{
    int res = 0;
    memset(match, -1, sizeof(match));
    for(int v = 0; v < V; v++)
    {
        if(match[v] < 0)
        {
            memset(used, 0, sizeof(used));
            if(dfs(v))
                res++;
        }
    }
    return res;
}

int r[maxn][maxn];
int c[maxn][maxn];
int rcnt[maxn];
int ccnt[maxn];

int main()
{
    //freopen("in.txt", "r", stdin);

    int T;
    scanf("%d", &T);
    while(T--)
    {
        memset(rcnt, 0, sizeof(rcnt));
        memset(ccnt, 0, sizeof(ccnt));


        int m, n;
        scanf("%d%d", &m, &n);
        V = (m + n) * 30;
        for(int i = 0; i < V; i++)
            G[i].clear();

        for(int i = 0; i < m; i++)
            scanf("%s", a[i]);

        for(int i = 0; i < m; i++)
        {
            bool flag = false;
            for(int j = 0; j < n; j++)
            {
                if(a[i][j] == '*')
                    flag = true;
                if(flag && a[i][j] == '#')
                {
                    r[i][rcnt[i]++] = j;    //记录每一段的终点/最大值(开区间)
                    flag = false;
                }
            }
            r[i][rcnt[i]++] = n;    //不太严谨,不过此题不影响结果
        }

        for(int j = 0; j < n; j++)
        {
            bool flag = false;
            for(int i = 0; i < m; i++)
            {
                if(a[i][j] == '*')
                    flag = true;
                if(flag == true && a[i][j] == '#')
                {
                    c[j][ccnt[j]++] = i;
                    flag = false;
                }
            }
            c[j][ccnt[j]++] = m;
        }

        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++)
            {
                if(a[i][j] == '*')
                {
                    int rloc;
                    for(int k = 0; k < rcnt[i]; k++)
                    {
                        if(j < r[i][k])
                        {
                            rloc = k;
                            break;
                        }
                    }

                    int cloc;
                    for(int k = 0; k < ccnt[j]; k++)
                    {
                        if(i < c[j][k])
                        {
                            cloc = k;
                            break;
                        }
                    }

                    addedge(i*30 + rloc, m*30 + j*30 + cloc);
                }
            }

        printf("%d\n", bipartite_matching());
    }

    return 0;
}

 

posted @ 2015-05-20 17:55  地鼠地鼠  阅读(167)  评论(0编辑  收藏  举报