最大流
拆点,男孩和女孩各拆成2个点ix,iy,jx,jy,互相喜欢ix->jx:1 不互相喜欢iy->jy:1
然后ix->iy=k,jy->jx=k,S->ix=ans,jy->T=ans
枚举ans跑最大流,不满流答案就是ans-1
#include<cstdio> #include<queue> #include<algorithm> #include<cstring> using namespace std; int en,n,k,level[1005],S,T,cur[1005],POINT_N,h[1005]; char s[55][55]; struct Edge{ int b,f,back,next; }e[1000005]; void AddEdge(int sa,int sb,int sc){ e[++en].b=sb; e[en].f=sc; e[en].back=en+1; e[en].next=h[sa]; h[sa]=en; swap(sa,sb); e[++en].b=sb; e[en].f=0; e[en].back=en-1; e[en].next=h[sa]; h[sa]=en; } int BFS(){ queue<int> Q; Q.push(S); memset(level,0,sizeof(level)); level[S]=1; while(!Q.empty()){ int u=Q.front(); Q.pop(); for(int i=h[u];i;i=e[i].next){ int v=e[i].b; if(level[v] || !e[i].f)continue; level[v]=level[u]+1; Q.push(v); } } return level[T]; } int DFS(int u,int flow){ if(u==T)return flow; int f=flow; for(int &i=cur[u];i;i=e[i].next){ int v=e[i].b,fl; if(level[v]==level[u]+1 && e[i].f && (fl=DFS(v,min(f,e[i].f)))){ e[i].f-=fl; e[e[i].back].f+=fl; f-=fl; if(f==0)return flow; } } return flow-f; } int Dinic(){ int ans=0; while(BFS()){ for(int i=1;i<=POINT_N;i++)cur[i]=h[i]; ans+=DFS(S,2100000000); } return ans; } int main(){ freopen("1305.in","r",stdin); freopen("1305.out","w",stdout); scanf("%d %d",&n,&k); for(int i=1;i<=n;i++)scanf("%s",s[i]+1); S=4*n+1; T=4*n+2; POINT_N=4*n+2; int ans=1; while(ans<=1000){ memset(h,0,sizeof(h)); for(int i=1;i<=n;i++){ AddEdge(i,i+n,k); AddEdge(i+3*n,i+2*n,k); } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(s[i][j]=='Y'){ AddEdge(i,j+2*n,1); } else { AddEdge(i+n,j+3*n,1); } } } for(int i=1;i<=n;i++){ AddEdge(S,i,ans); AddEdge(i+2*n,T,ans); } int an=Dinic(); //printf("%d\n",ans); if(an<ans*n){printf("%d\n",ans-1);return 0;} ans++; } return 0; }