ZOJ1516_Uncle Tom's Inherited Land_二分图(匈牙利算法)

本文介绍了一种通过构建二分图并使用匈牙利算法来解决01矩阵中寻找最多可分割成1*2矩阵数量的问题。核心思路在于将相邻的0视为节点,并在它们之间建立边,最终通过最大匹配数确定分割的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意
给一个01矩阵,求最对能分割出几块由0构成的1 * 2的矩阵
思路
抽象出二分图,相邻的0之间建边,匈牙利算法求最大匹配数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#define INF 0x3f3f3f3f
#define rep0(i, n) for (int i = 0; i < n; i++)
#define rep1(i, n) for (int i = 1; i <= n; i++)
#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)
#define rep_1(i, n) for (int i = n; i > 0; i--)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
#define MAXN 110

using namespace std;
struct Edge
{
    int from, to;
    Edge(int f, int t) : from(f), to(t) {}
};
vector<Edge> edges;
vector<int> g[MAXN * MAXN];
int land[MAXN][MAXN], matching[MAXN * MAXN], check[MAXN * MAXN];
void addEdge(int from, int to)
{
    edges.push_back(Edge(from, to));
    g[from].push_back(edges.size() - 1);
    edges.push_back(Edge(to, from));
    g[to].push_back(edges.size() - 1);
}
int n, m, k;
bool dfs(int u)
{
    for (int i = 0; i < g[u].size(); i++)
    {
        int v = edges[g[u][i]].to;
        if (check[v])
            continue;
        check[v] = 1;
        if (matching[v] == -1 || dfs(matching[v]))
        {
            matching[v] = u;
            matching[u] = v;

            return true;
        }
    }
    return false;
}
int hungarian()
{
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = (i - 1) % 2 + 1; j <= m; j += 2)
        {
            if (land[i][j] == 1)
                continue;
            mem(check, 0);

            if (dfs((i - 1) * m + j))
                ans++;
        }
    }
    return ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif // ONLINE_JUDGE

    while (~scanf("%d %d %d", &n, &m, &k) && n)
    {
        mem(land, 0);
        mem(matching, -1);
        int a, b;
        edges.clear();
        rep1(i, n * m)
            g[i].clear();
        while (k--)
        {
            scanf("%d %d", &a, &b);
            land[a][b] = 1;
        }
        rep1(i, n)
        {
            rep1(j, m)
            {
                if (land[i][j] == 1)
                    continue;
                if (i > 1 && land[i - 1][j] == 0)
                    addEdge((i - 1) * m + j, (i - 2) * m + j);
                if (j > 1 && land[i][j - 1] == 0)
                    addEdge((i - 1) * m + j, (i - 1) * m + j - 1);
            }
        }
        printf("%d\n", hungarian());


    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值