在一块 n imes mn×m 的地面上,有一些格子是泥泞的,有一些格子是干净的。现在需要用一些宽度为 11 、长度任意的木板把泥地盖住,同时不能盖住干净的地面,木板可以重叠。求最少需要多少块木板。 n,m leq 50n,m≤50 。
22 要素:每块泥地要么被横着的木板盖住,要么被竖着的木板盖住。
横着的木板只能放在同一行若干个连续的泥地上,称这种连续的泥地为行泥泞块;竖着的木板只能放在同一列若干个连续的泥地上,称这种连续的泥地为列泥泞块。
把行泥泞块作为左部节点,列泥泞块作为右部节点。对于每块泥地,在其对应的行泥泞块和列泥泞块之间连边。
求出这张二分图的最小覆盖即可。
注意 这题和那个棋盘车的题目不一样!!!行列建图显然是错的
要特殊的以横板为左图 竖版为右图来建图!
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 55; const int M = N*N; char a[N][N]; int row[N][N],col[N][N]; int R,C; bool vis[M]; int linker[M]; int to[M],nxt[M]; int head[M],tot; int n, m; void addedge(int u, int v) { ++tot; to[tot] = v; nxt[tot] = head[u]; head[u] = tot; } bool dfs(int u) { for(int i = head[u]; ~i; i = nxt[i]) { int v = to[i]; if(!vis[v]) { vis[v] = 1; if(linker[v]==-1 || dfs(linker[v])) { linker[v] = u; return 1; } } } return 0; } int hungary() { int ret = 0; memset(linker, -1, sizeof(linker)); for(int i = 1; i <= R; ++i) { memset(vis, 0, sizeof(vis)); if(dfs(i)) ++ret; } return ret; } int main() { while(~scanf("%d %d", &n, &m)) { memset(row, 0, sizeof(row)); memset(col, 0, sizeof(col)); memset(head, -1, sizeof(head)); tot = -1; R = C = 0; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) { cin >> a[i][j]; if(a[i][j]=='*') { if(row[i][j-1]) row[i][j] = row[i][j-1]; else row[i][j] = ++R; if(col[i-1][j]) col[i][j] = col[i-1][j]; else col[i][j] = ++C; } } for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) if(a[i][j]=='*') addedge(row[i][j], col[i][j]); printf("%d ", hungary()); } return 0; }