题意:一个row*col的矩阵表示一块田地,'*'表示湿地,'.'表示草地。现在FJ要在田地上铺木板盖掉所有的湿地,露出所有的草地。每块木板的宽度为1,长度为任意长。问FJ最少用几块木板就可以完成任务?
思路:匈牙利算法的最小点覆盖。将每行所含有的每一段做为一侧的点,将每列所含有的每一段作为另一侧的点,就是对每一段'*'赋给一个新的x,y坐标,使得不同的段x,y不同。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <queue>
#include <map>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-3
#define maxn 100010
#define MOD 1000000007
int n,m,t1,t2;
char s[5050][5050];
int mp[5050][5050];
int mx[5050][5050],my[5050][5050];
int match[5050],vis[5050];
int dfs(int x)
{
for(int i = 1; i < t2; i++)
if(mp[x][i] && !vis[i])
{
vis[i] = 1;
if(!match[i] || dfs(match[i]))
{
match[i] = x;
return 1;
}
}
return 0;
}
int main()
{
int t,C = 1;
//scanf("%d",&t);
while(scanf("%d%d",&n,&m) != EOF)
{
memset(match,0,sizeof(match));
for(int i = 0; i < n; i++)
scanf("%s",s[i]);
t1 = 1,t2 = 1;
for(int i = 0; i < n; i++)
{
if(s[i][0] == '*')
mx[i][0] = t1;
for(int j = 1; j < m; j++)
{
if(s[i][j] == '*')
mx[i][j] = t1;
else if(s[i][j-1] == '*')
t1++;
}
if(s[i][m-1] == '*')
t1++;
}
for(int i = 0; i < m; i++)
{
if(s[0][i] == '*')
my[0][i] = t2;
for(int j = 1; j < n; j++)
{
if(s[j][i] == '*')
my[j][i] = t2;
else if(s[j-1][i] == '*')
t2++;
}
if(s[n-1][i] == '*')
t2++;
}
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(s[i][j] == '*')
mp[mx[i][j]][my[i][j]] = 1;
int ans = 0;
for(int i = 0; i < t1; i++)
{
memset(vis,0,sizeof(vis));
ans += dfs(i);
}
printf("%d\n",ans);
}
}