传送门点击打开链接
题目大意 :给出n*m的矩阵,若矩阵该位置为1,则为一个人,若为2则为一台电脑,若为0,则为空地,求最大匹配人数。
(匹配的意思是如果一个人相邻有两台电脑,且这两台电脑不在同一行或者同一列,即人,两台电脑在矩阵中构成了‘L’型,则算一种匹配,一台电脑只能和一个人匹配。)
(n,m<=500)
思路:首先我们意识到一个人所匹配的电脑一定是不同行的,即不同奇偶,奇偶让我们想到了什么?二分图匹配,选一个匹配的过程就变成了选一个奇数行的电脑->选一个与该电脑相邻的人->再选一个与这个人相邻的偶数行的电脑….
所以我们就连上<s,odd,1>,<odd,person,1>,<preson,even,1>三种边,然后最大流跑就是了。
是吗?当然不是上面那样、
如果我们这样连边跑最大流,那么一个人可能会被用到两次?所以明显是错的!!!
(当时真的是wa死我了…..)。
怎么解决呢?我们这样连边:
<s,odd,1>,<odd,person_in,1>,<preson_in,preson_out,1>,<person_out,even,1>,<even,t,1>/
什么意思呢?我们将每个人拆成两个点,一个流入,一个流出,流入点和流出点连一条流量为1的边,就可以限制每个人只匹配一次了..(我居然连这个都没想到….)。
#include<iostream> #include<cstring> #include<cstdlib> #include<string> #include<cstdio> #include<algorithm> #include<cmath> #include<ctime> #define inf 1000000000 using namespace std; struct edge{int to;int next;int flow; };edge bian[5000010]; int size=1,first[3000010],head,tail,dis[3000010],p[5000010],s,t,n,m,A[550][550]; bool exist[3000010]; int pos1(int x,int y) {return (x-1)*m+y;} int pos2(int x,int y) {return m*n+(x-1)*m+y;} void inser(int x,int y,int z) { bian[++size].to=y; bian[size].next=first[x]; bian[size].flow=z; first[x]=size; bian[++size].to=x; bian[size].next=first[y]; bian[size].flow=0; first[y]=size; } bool bfs(int x,int y) { memset(dis,127,sizeof(dis)); dis[x]=0; head=0,tail=1;p[1]=x; memset(exist,false,sizeof(exist)); while(head!=tail) { int k=p[++head]; exist[k]=false; for(int u=first[k];u;u=bian[u].next) { if(dis[bian[u].to]>=9000000&&bian[u].flow>0) { dis[bian[u].to]=dis[k]+1; if(!exist[bian[u].to]) { p[++tail]=bian[u].to; exist[bian[u].to]=true; } } } } return dis[y]<=9000000; } int dfs(int x,int F) { if(x==t) return F; int ret=0; for(int u=first[x];u&&F>0;u=bian[u].next) { if(bian[u].flow>0&&dis[bian[u].to]==dis[x]+1) { int f=dfs(bian[u].to,min(F,bian[u].flow)); F-=f; bian[u].flow-=f; bian[u^1].flow+=f; ret+=f; } } if(F==0||ret==0) dis[x]=-5; return ret; } int maxflow(int x,int y) { int ret=0; while(bfs(x,y)) ret+=dfs(x,1000000000); return ret; } int main() { freopen("gugleseating.in","r",stdin); freopen("gugleseating.out","w",stdout); scanf("%d%d",&n,&m); memset(A,0,sizeof(A)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&A[i][j]); s=0,t=2*n*m+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(A[i][j]==2) { if(i%2==1) { inser(s,pos1(i,j),1); if(A[i-1][j]==1&&i-1>=1) inser(pos1(i,j),pos1(i-1,j),1); if(A[i][j-1]==1&&j-1>=1) inser(pos1(i,j),pos1(i,j-1),1); if(A[i][j+1]==1&&j+1<=m) inser(pos1(i,j),pos1(i,j+1),1); if(A[i+1][j]==1&&i+1<=n) inser(pos1(i,j),pos1(i+1,j),1); } else { inser(pos1(i,j),t,1); if(A[i-1][j]==1&&i-1>=1) inser(pos2(i-1,j),pos1(i,j),1); if(A[i][j-1]==1&&j-1>=1) inser(pos2(i,j-1),pos1(i,j),1); if(A[i][j+1]==1&&j+1<=m) inser(pos2(i,j+1),pos1(i,j),1); if(A[i+1][j]==1&&i+1<=n) inser(pos2(i+1,j),pos1(i,j),1); } } else if(A[i][j]==1) inser(pos1(i,j),pos2(i,j),1); } cout<<maxflow(s,t); return 0; }