题目就是问如何用最小的板覆盖所有的草地。可以横着放,也可以竖着放,允许一个草地放多个点。
建图方法就是 每个横向的草地作为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; }
poj 2226 二分图 最小点覆盖 , 最大流
时间: 2024-10-12 23:37:26