每个人拆成$2$个点,表示是否与喜欢的人跳舞
跳$m$首舞曲时,满足最大流为$n*m$
二分$m$,跑最大流即可
#include<cstdio> #include<cstring> inline int min(int A,int B){return A<B?A:B;} #define W 9999 int n,k,S,T,cur[W],d[W],L,R,h[W]; char q[55][55]; bool vis[W]; int Cnt,hd[W],nxt[W],ed[W],poi[W],val[W]; void adde(int x,int y,int v){ nxt[ed[x]]=++Cnt; hd[x]=hd[x]?hd[x]:Cnt; ed[x]=Cnt; poi[Cnt]=y; val[Cnt]=v; } inline void link(int x,int y,int v){adde(x,y,v),adde(y,x,0);} #define to poi[i] bool bfs(){ for(int i=1;i<=T;++i) cur[i]=hd[i],vis[i]=0; h[L=1]=S; R=2; vis[S]=1; while(L!=R){ int x=h[L++]; if(L>=W)L=1; for(int i=hd[x];i;i=nxt[i]) if(!vis[to]&&val[i]){ vis[to]=1,d[to]=d[x]+1; h[R++]=to; if(R>=W)R=1; } }return vis[T]; } int dfs(int x,int a){ if(x==T||!a) return a; int F=0,f; for(int &i=cur[x];i;i=nxt[i]){ if(d[to]==d[x]+1&&(f=dfs(to,min(a,val[i])))>0) F+=f,a-=f,val[i]-=f,val[i^1]+=f; if(!a) break; }return F; } int dinic(){int re=0; while(bfs())re+=dfs(S,W); return re;} int chk(int x){ memset(hd,0,sizeof(hd)); Cnt=1; memset(ed,0,sizeof(ed)); memset(nxt,0,sizeof(nxt)); for(int i=1;i<=n;++i) link(S,i,x),link(i+n*3,T,x); for(int i=1;i<=n;++i){ link(i,i+n,k); link(i+n*2,i+n*3,k); for(int j=1;j<=n;++j){ if(q[i][j]=='Y') link(i,j+n*3,1); else link(i+n,j+n*2,1); } }return dinic()==x*n; } int main(){ scanf("%d%d",&n,&k); S=n*4+1,T=S+1; for(int i=1;i<=n;++i) scanf("%s",q[i]+1); int l=1,r=n+1; while(l<r){ int mid=(l+r)/2; if(chk(mid)) l=mid+1; else r=mid; }printf("%d",l-1); return 0; }