http://poj.org/problem?id=2226
题意就是 给你一个r*c的矩阵。里面有一些*和.,要求用最少的操作去掉所有的*
每次的操作就是去掉一行连续的*,或者一列(长度任意)
。。但是这个题有个不一样的地方是, 每次操作不能碰到 点. 因此就是说不能粗暴的把整行去掉
之前的POJ3041就可以以点为边,对于点(x,y),只要对行x或着列y进行删除操作 都可以把点(x,y)抹去,也就是说,把行和列看作点,把点(x,y)看作边,把x行和y列连一条边, 最后只要找最少的x或y 覆盖所有的“边”即可
而这里也是同样,只不过 这里的行 操作不再是R行,而是先预处理一遍,看有多少连续的行,算出每个点所在 的第几个连续行里
例如: *....* 的两个星号分别在第一个连续行操作,和第二个连续行操作。
因此 最后还是 把点(x,y)看成边,不过连接的点 分别是 该点所在的第i个连续行,和j个连续列,最后求一次最小点覆盖即可
注意。连续行/列的数量可能超过 R/C
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
char tm[51][51];
int min(int a,int b)
{return a<b?a:b;}
int row[51][51];
int col[51][51];
int g[51*51][51*51];
int uN,vN;
const int MAXN = 51*51;
int linker[MAXN];
bool used[MAXN];
bool dfs(int u)
{
for (int v=0;v<vN;v++)
if (g[u][v]&&!used[v])
{
used[v]=true;
if (linker[v]==-1||dfs(linker[v]))
{
linker[v]=u;
return true;
}
}
return false;
}
int hungary()
{
int res=0;
memset(linker,-1,sizeof(linker));
for (int u=0;u<uN;u++)
{
memset(used,false,sizeof(used));
if (dfs(u)) res++;
}
return res;
}
int main()
{
int i,j;
int r,c;
cin>>r>>c;
for (i=1;i<=r;i++)
scanf("%s",tm[i]+1);
int cun=0;
for (i=1;i<=r;i++)
{
for (j=1;j<=c;j++)
{
if (tm[i][j]=='.') continue;
++cun;
while(tm[i][j]=='*'&&j<=c)
{
row[i][j]=cun;
j++;
}
}
}
uN=cun;
cun=0;
for (i=1;i<=c;i++)
{
for (j=1;j<=r;j++)
{
if (tm[j][i]=='.') continue;
++cun;
while(tm[j][i]=='*'&&j<=r)
{
col[j][i]=cun;
j++;
}
}
}
vN=cun;
for (i=1;i<=r;i++)
{
for (j=1;j<=c;j++)
{
if (tm[i][j]=='.') continue;
int x=row[i][j];
int y=col[i][j];
g[x-1][y-1]=1;
}
}
int ret=hungary();
printf("%d\n",ret);
return 0;
}