Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 7773 | Accepted: 2866 |
Description
Input
Output
Sample Input
4 4 *.*. .*** ***. ..*.
Sample Output
4
Hint
Source
题目链接:POJ 2226 Muddy Fields
题目大意:给你一块n*m的方格型农场,其中' * '是泥地,' . '是草地,你可以用一块任意长的木板覆盖一行或一列中连续的泥地,其中木板之间可以相互覆盖。问要将所有的泥地覆盖需要至少多少的木板?
题目分析:对每一块泥地,预处理出最优情况下它被覆盖时覆盖他的行木板的编号X[ i ][ j ]以及列木板的编号Y[ i ][ j ]。什么时候是最优情况?当且仅当该泥地与同一行连续或者同一列连续的泥地同一编号。这样在预处理之后就成功将行列二分,符合二分图的性质,将题目转化为二分图的最小点覆盖。对每块木板建边(X[ i ][ j ], Y[ i ][ j ]),求最大匹配即可。(最大匹配 = 最小点覆盖)
建图:每遇到一次草地就对编号++,每遇到泥地,泥地编号等于当前编号。
代码如下:
#include <stdio.h> #include <string.h> #include <algorithm> #define clear(A, X, SIZE) memset(A, X, sizeof(A[0]) * (SIZE + 1)) using namespace std; const int maxN = 2500; const int maxE = 1000000; struct Edge{ int v, n; }edge[maxE]; int adj[maxN], cntE, vis[maxN], link[maxN], X[maxN][maxN], Y[maxN][maxN]; int n, m, row, col; char s[maxN][maxN]; void addedge(int u, int v){ edge[cntE].v = v; edge[cntE].n = adj[u]; adj[u] = cntE++; } int find(int u){ for(int i = adj[u]; ~i; i = edge[i].n) if(!vis[edge[i].v]){ int v = edge[i].v; vis[v] = 1; if(link[v] == -1 || find(link[v])){ link[v] = u; return 1; } } return 0; } int match(){ int ans = 0, i; clear(link, -1, col); for(i = 1; i <= row; ++i){ clear(vis, 0, col); ans += find(i); } return ans; } void work(){ row = 1, col = 1; for(int i = 0; i < n; ++i) scanf("%s", s[i]); for(int i = 0; i < n; ++i, ++row) for(int j = 0; j < m; ++j){ if(s[i][j] == '*') X[i][j] = row; else X[i][j] = 0, ++row; } for(int i = 0; i < m; ++i, ++col) for(int j = 0; j < n; ++j){ if(s[j][i] == '*') Y[j][i] = col; else Y[j][i] = 0, ++col; } --row, --col; clear(adj, -1, row); cntE = 0; for(int i = 0; i < n; ++i) for(int j = 0; j < m; ++j){ if(X[i][j]) addedge(X[i][j], Y[i][j]); } printf("%d\n", match()); } int main(){ while(~scanf("%d%d", &n, &m)) work(); return 0; }