题目大意:给定n个男生和n个女生,一些互相喜欢而一些不。举行几次舞会,每次舞会要配成n对。不能有同样的组合出现。每一个人仅仅能与不喜欢的人跳k次舞,求最多举行几次舞会
将一个人拆成两个点。点1向点2连一条流量为k的边。两个人若互相喜欢则点1之间连边,不喜欢则点2之间连边
对于每个要验证的x值 将每个人的点1向源或汇连一条流量为x的边
然后二分答案跑最大流就可以
#include#include #include #include #define M 220#define INF 0x3f3f3f3f#define S 0#define T (n<<2|1)using namespace std;struct abcd{ int to,f,next;}table[100100];int head[M],tot=1;int n,k;char s[M];int dpt[M];bool BFS(){ static int q[M],r,h; int i; memset(dpt,-1,sizeof dpt); r=h=0;q[++r]=S;dpt[S]=1; while(r!=h) { int x=q[++h]; for(i=head[x];i;i=table[i].next) if(table[i].f&&!~dpt[table[i].to]) { dpt[table[i].to]=dpt[x]+1; q[++r]=table[i].to; if(table[i].to==T) return true; } } return false;}int Dinic(int x,int flow){ int i,left=flow; if(x==T) return flow; for(i=head[x];i&&left;i=table[i].next) if(table[i].f&&dpt[table[i].to]==dpt[x]+1) { int temp=Dinic(table[i].to, min(left,table[i].f) ); if(!temp) dpt[table[i].to]=-1; left-=temp; table[i].f-=temp; table[i^1].f+=temp; } return flow-left;}inline void Add(int x,int y,int z){ table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot;}inline void Link(int x,int y,int z){ Add(x,y,z); Add(y,x,0);}inline void Restore(){ int i; for(i=2;i<=tot;i+=2) table[i].f+=table[i^1].f,table[i^1].f=0;}bool Judge(int x){ int i; Restore(); for(i=tot-(n<<2)+1;i<=tot;i+=2) table[i].f=x; int ans=0; while( BFS() ) ans+=Dinic(S,INF); return ans==n*x;}int Bisection(){ int l=0,r=n; while(l+1 >1; if( Judge(mid) ) l=mid; else r=mid; } if( Judge(r) ) return r; return l;}int main(){ int i,j; cin>>n>>k; for(i=1;i<=n;i++) { Link(i,n+i,k); Link(n+n+i,n+n+n+i,k); } for(i=1;i<=n;i++) { scanf("%s",s+1); for(j=1;j<=n;j++) { if(s[j]=='Y') Link(i,n+n+n+j,1); else Link(n+i,n+n+j,1); } } for(i=1;i<=n;i++) { Link(S,i,0); Link(n+n+n+i,T,0); } cout< <