背景
随着时代的演进,困难的刑案也不断增加...
但真相只有一个
虽然变小了,头脑还是一样好,这就是名侦探柯南!
描述
[CoVH06]
面对OIBH组织的嚣张气焰, 柯南决定深入牛棚, 一探虚实.
他经过深思熟虑, 决定从OIBH组织大门进入...........
OIBH组织的大门有一个很神奇的锁.
锁是由M*N个格子组成, 其中某些格子凸起(灰色的格子). 每一次操作可以把某一行或某一列的格子给按下去.
如果柯南能在组织限定的次数内将所有格子都按下去, 那么他就能够进入总部. 但是OIBH组织不是吃素的, 他们的限定次数恰是最少次数.
请您帮助柯南计算出开给定的锁所需的最少次数.
格式
输入格式
第一行 两个不超过100的正整数N, M表示矩阵的长和宽
以下N行 每行M个数 非0即1 1为凸起方格
输出格式
一个整数 所需最少次数
限制
全部1秒
水题,走一遍模板即可,注意输入的处理
将每一行看作一个X结点,每一列看作一个Y结点,每个目标对应一条边。这样,把所有格子给按下去.意味着每条边至少有一个点被选中。那么,本题的模型是二分图最小点覆盖,即选择尽量少的点,使得每条边至少有一个端点被选中。可以证明,最小点覆盖数等于最大匹配。那么本题就转变为求二分图的最大匹配。
/*
Accepted,
time = 39 ms,
mem = 556 KiB,
score = 100
*/
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN = 105;
int map[MAXN][MAXN];
int link[MAXN];
int vis[MAXN];
char temp[MAXN];
int n, m;
bool find(int x)
{
for (int i = 0; i < m; i++)
{
if (map[x][i] && !vis[i])
{
vis[i] = 1;
if (link[i] == -1 || find(link[i]))
{
link[i] = x;
return true;
}
}
}
return false;
}
int main()
{
cin >> n >> m;
memset(link, -1, sizeof(link));
memset(map, 0, sizeof(map));
int ans = 0;
for (int i = 0; i < n; i++)//注意输入的处理
{
cin >> temp;
for (int j = 0; j < m; j++)
{
if (temp[j] == '1')
{
map[i][j] = 1;
}
}
}
for (int i = 0; i < n; i++)
{
memset(vis, 0, sizeof(vis));
if (find(i))
{
ans++;
}
}
cout << ans << endl;
return 0;
}