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; }