Description
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
Input
第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为‘Y‘当且仅当男孩i和女孩j相互喜欢。
Output
仅一个数,即舞曲数目的最大值。
Sample Input
YYY
YYY
YYY
Sample Output
HINT
N<=50 K<=30
这个题思路很妙啊……第一次做到在网络流中使用二分的题目
其实一开始想到用二分限制的,不过并没有深入思考下去
而是写了一个别人几行就能实现我却用网络流实现的贪心
正解是拆点加二分。
因为答案满足单调性,若可以跳x首曲子,则x-1首肯定也是可以的
建图?
将每个男生和女生拆成两个点:Yes和No
超级源点连接男生的Yes,超级汇点连接女生的Yes
容量设置为二分的x。若跑出来最大流是x*n,就说明满流了
满流即为可以满足x首曲子
对于互相喜欢的,我们在男女的两个Yes点间连边
不喜欢的,我们就在男女的两个No点间连边
那么如何限制k呢?
每个男Yes连自己的No,容量为k
每个女No连自己Yes,容量为k
这样就可以保证k了
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #define MAXM (100000+10) #define MAXN (10000+10) using namespace std; struct node { int Flow; int next; int to; }edge[MAXM*2]; int Depth[MAXN],q[MAXN]; int head[MAXN],num_edge; int n,m,k,s,e,d,INF; int a[MAXN][MAXN]; char ch[1010]; void add(int u,int v,int l) { edge[++num_edge].to=v; edge[num_edge].Flow=l; edge[num_edge].next=head[u]; head[u]=num_edge; } bool Bfs(int s,int e) { int Head=0,Tail=1; memset(Depth,0,sizeof(Depth)); Depth[s]=1; q[1]=s; while (Head<Tail) { ++Head; int x=q[Head]; for (int i=head[x];i!=0;i=edge[i].next) if (!Depth[edge[i].to] && edge[i].Flow>0) { Depth[edge[i].to]=Depth[x]+1; q[++Tail]=edge[i].to; } } if (Depth[e]>0) return true; return false; } int Dfs(int x,int low) { int Min,f=0; if (x==e || low==0) return low; for (int i=head[x];i!=0;i=edge[i].next) if (edge[i].Flow>0 && Depth[edge[i].to]==Depth[x]+1 && (Min=Dfs(edge[i].to , min(low,edge[i].Flow) ))) { edge[i].Flow-=Min; edge[((i-1)^1)+1].Flow+=Min; f+=Min; low-=Min; } return f; } int Dinic(int s,int e) { int Ans=0; while (Bfs(s,e)) Ans+=Dfs(s,0x7fffffff); return Ans; } void Addline(int x) { memset(head,0,sizeof(head)); memset(edge,0,sizeof(edge)); num_edge=0; for (int i=1;i<=n;++i) { add(0,i+520,x); add(i+520,0,0);//超级源点 add(i+n+520,999,x);//超级汇点 add(999,i+n+520,0); add(i+520,i+250,k); add(i+250,i+520,0); add(i+n+250,i+n+520,k); add(i+n+520,i+n+250,0); } for (int i=1;i<=n;++i) { for (int j=1;j<=n;++j) if (a[i][j]==1) { add(i+520,j+n+520,1); add(j+n+520,i+520,0); } else { add(i+250,j+n+250,1); add(j+n+250,i+250,0); } } } int main() { s=0,e=999; memset(&INF,0x7f,sizeof(INF)); scanf("%d%d",&n,&k); for (int i=1;i<=n;++i) { scanf("%s",ch); for (int j=1;j<=n;++j) a[i][j]=(ch[j-1]==‘Y‘); } int l=0,r=n*n; while (l<r) { int mid=(l+r+1)/2; Addline(mid); int Max=Dinic(0,999); if (Max==mid*n) l=mid; else r=mid-1; } cout<<l<<endl; }