【题目链接】 http://poj.org/problem?id=2226
【题目大意】
给出一张图,上面有泥和草地,有泥的地方需要用1*k的木板覆盖,
有草地的地方不希望被覆盖,问在此条件下需要的最少木板数目
【题解】
我们将四周都当成草地,将每块草地拆成横向点和纵向点
对于每一块泥地,我们将其向左和向上遇到的第一块草地连线,
对于这个图的最小点覆盖就是答案,而最小点覆盖等于二分图的最大匹配,
因此我们做一遍最大匹配即可
【代码】
#include <cstdio> #include <algorithm> #include <cstring> #include <vector> #include <queue> using namespace std; const int MAX_V=10000; int V,match[MAX_V]; vector<int> G[MAX_V]; bool used[MAX_V]; void add_edge(int u,int v){ G[u].push_back(v); G[v].push_back(u); } bool dfs(int v){ used[v]=1; for(int i=0;i<G[v].size();i++){ int u=G[v][i],w=match[u]; if(w<0||!used[w]&&dfs(w)){ match[v]=u; match[u]=v; return 1; } }return 0; } int bipartite_matching(){ int res=0; memset(match,-1,sizeof(match)); for(int v=0;v<V;v++){ if(match[v]<0){ memset(used,0,sizeof(used)); if(dfs(v))res++; } }return res; } const int MAX_N=60; char mp[MAX_N][MAX_N]; int g[MAX_N][MAX_N][2]; int T,N,M; void init(){ memset(g,0,sizeof(g)); for(int i=0;i<N;i++){ scanf("%s",mp[i]); } } void solve(){ int mark=1,cnt=0; for(int i=0;i<N;i++){ for(int j=0;j<M;j++){ if(mp[i][j]=='.')g[i][j][0]=-1,cnt++; else g[i][j][0]=cnt,mark=1; }if(mark)cnt++; } for(int j=0;j<M;j++){ mark=0; for(int i=0;i<N;i++){ if(mp[i][j]=='.')cnt++; else g[i][j][1]=cnt,mark=1; }if(mark)cnt++; } for(int i=0;i<N;i++){ for(int j=0;j<M;j++)if(~g[i][j][0]){ add_edge(g[i][j][0],g[i][j][1]); } }V=cnt; printf("%d ",bipartite_matching()); for(int i=0;i<=V;i++)G[i].clear(); } int main(){ while(~scanf("%d%d",&N,&M)){ init(); solve(); }return 0; }