题目就是问如何用最小的板覆盖所有的草地。可以横着放,也可以竖着放,允许一个草地放多个点。
建图方法就是 每个横向的草地作为X,纵向连续的草地作为Y. X连接Y的边表示, 这里有他们的公共点。。
很显然,覆盖所有草地,就是覆盖所有的边 ,二分图中,最小点覆盖 = 最大匹配
= =其实如果存在一条边未被选中的节点覆盖,则必然存在一条对应的增广路径
//tpl
//ipqhjjybj_tpl.h
//header.h
#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define rep(i,j,k) for(int i = j; i < k;i++)
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 500;
int g[N][N];
int cx[N],cy[N];
int mark[N];
int nx,ny;
int dfs(int u)
{
rep(v,0,ny)
{
if(g[u][v]&&!mark[v])//u和v不要搞反了
{
mark[v]=1;
if(cy[v]==-1||dfs(cy[v]))
{
cx[u]=v;
cy[v]=u;
return 1;
}
}
}
return 0;
}
int maxmatch()
{
int res=0;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
rep(i,0,nx)
{
if(cx[i]==-1)
{
memset(mark,0,sizeof(mark));
res+=dfs(i);
}
}
// rep(i,0,nx){
// printf("cx[%d] = %d\n",i,cx[i]);
// printf("cy[%d] = %d\n",i,cy[i]);
// }
return res;
}
int a[N][N],b[N][N];
char s[N][N];
int main(){
int n,m;
while(scanf("%d %d",&n,&m)!=EOF){
memset(g,0,sizeof(g));
rep(i,0,n) scanf("%s",s[i]);
int cnt = 0;
rep(i,0,n)
rep(j,0,m){
if(s[i][j]=='*'){
if(i==0 || s[i-1][j]=='.')
a[i][j] = cnt++;
else a[i][j] = a[i-1][j];
}
}
nx = cnt;
cnt = 0;
rep(i,0,n)
rep(j,0,m){
if(s[i][j] == '*'){
if(j==0 || s[i][j-1]=='.')
b[i][j] = cnt++;
else b[i][j] = b[i][j-1];
g[a[i][j]][b[i][j]] = 1;
}
}
ny = cnt;
// rep(i,0,nx){
// rep(j,0,ny)
// printf("g[%d][%d]=%d ",i,j,g[i][j]);
// printf("\n");
// }
printf("%d\n",maxmatch());
}
return 0;
}
附上我的 最大流写法。。
//tpl
//ipqhjjybj_tpl.h
//header.h
#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define rep(i,j,k) for(int i = j; i < k;i++)
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1111;
int tot;
int s,t;
int sum;
struct node{
int u,v,w,next;
node(){}
node(int _u,int _v,int _w,int _next){
u=_u,v=_v,w=_w,next=_next;
}
}edge[N*N];
int head[N],cur[N],dis[N];
int pre[N],gap[N],aug[N];
const int oo=0x3f3f3f;
void addEdge(int u,int v,int w){
edge[tot]=node(u,v,w,head[u]);
head[u]=tot++;
edge[tot]=node(v,u,0,head[v]);
head[v]=tot++;
}
int SAP(int s,int e,int n){
int max_flow=0,v,u=s;
int id,mindis;
aug[s]=oo;
pre[s]=-1;
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
gap[0]=n;
for(int i=0;i <= n;i++)
cur[i]=head[i];
while(dis[s]<n){
if(u==e){
max_flow += aug[e];
for(v=pre[e]; v!=-1; v=pre[v]){
int ed=cur[v];
edge[ed].w -= aug[e];
edge[ed^1].w += aug[e];
aug[v]-=aug[e];
if(edge[ed].w==0) u=v;
}
}
bool flag=false;
for(id=cur[u]; id!=-1;id=edge[id].next){
v=edge[id].v;
if(edge[id].w > 0 && dis[u]==dis[v]+1){
flag=true;
pre[v]=u;
cur[u]=id;
aug[v]=min(aug[u],edge[id].w);
u=v;
break;
}
}
if(flag==false){
if(--gap[dis[u]] == 0) break;
int mindis=n;
for(id=head[u]; id!=-1; id=edge[id].next){
v=edge[id].v;
if(edge[id].w>0 && dis[v] < mindis){
mindis = dis[v];
cur[u]=id;
}
}
dis[u] = mindis + 1;
gap[dis[u]]++;
if(u!=s)u=pre[u];
}
}
return max_flow;
}
int a[N][N],b[N][N];
char ss[N][N];
int main(){
int n,m;
while(scanf("%d %d",&n,&m)!=EOF){
tot=sum=s=0;
int tc=0;
memset(head,-1,sizeof(head));
rep(i,0,n) scanf("%s",ss[i]);
int cnt = 0;
t = ++cnt;
rep(i,0,n)
rep(j,0,m){
if(ss[i][j]=='*'){
if(i==0 || ss[i-1][j]=='.')
a[i][j] = ++cnt , addEdge(s,a[i][j],1);
else a[i][j] = a[i-1][j];
}
}
rep(i,0,n)
rep(j,0,m){
if(ss[i][j] == '*'){
if(j==0 || ss[i][j-1]=='.')
b[i][j] = ++cnt ,addEdge(b[i][j],t,1);
else b[i][j] = b[i][j-1];
//g[a[i][j]][b[i][j]] = 1;
addEdge(a[i][j],b[i][j],1);
}
}
printf("%d\n",SAP(s,t,cnt+1));
}
return 0;
}