题目描述
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。
有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。
给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
数据范围
样例输入
【输入1】
3 0
YYY
YYY
YYY
【输入2】
3 0
YYY
YYN
YNY
【输入3】
2 0
YN
YN
【输入4】
2 1
YN
YN
样例输出
【输出1】3
【输出2】2
【输出3】0
【输出4】1
解题思路
不知为何,我们学校OJ把这道题rejudge(应该是吧)了,数据也由10组增加成了20组,我原来AC了的代码也wrong了。。。于是从写此题
建图: ①每个点拆成2个点,加上源点汇点,也就是4n+2个点。
②起点向男生的第一个点连边,权值为k(二分用)
③女生的第二个点向汇点连边,权值为k(二分用)
④如果男生A,与女生B互相喜欢,则男生的第一个点向女生的第二个点连边,否则男生的第二个点向女生的第一个点连边。(权值为1)
⑤男生的第一个点向男生的第二个点连边,权值为k(题目中的k)
⑥女生的第一个点向女生的第二个点连边,权值为k(题目中的k)
⑦然后二分k,如果满流(流量为n*k(k为二分的k))则成立。
⑧答案就是k(二分的k。。)
其实我是直接用残余网络跑的,只需判断流量是否为n就行其实感觉与二分并没有什么区别,反正n都这么小。
代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define Maxn 233333
#define Maxe 233333
using namespace std;
inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
int S,T,N,cnt=0,dis[Maxn],GAP[Maxn],h[Maxn],Map[505][505];
struct node{int to,next,v,pair;}e[Maxe];
void AddEdge(int x,int y,int v,int pair){e[cnt]=(node){y,h[x],v,pair};h[x]=cnt;}
void AddEdge(int x,int y,int v){AddEdge(x,y,v,++cnt+1);AddEdge(y,x,0,++cnt-1);}
int SAP(int x,int Maxflow){
if(x==T)return Maxflow;
int tmp=Maxflow;
for(int p=h[x];p;p=e[p].next){
int y=e[p].to;
int flow=min(tmp,e[p].v);
if(flow&&dis[x]==dis[y]+1){
int ret=SAP(y,flow);
tmp-=ret;
e[p].v-=ret;
e[e[p].pair].v+=ret;
if(!tmp||dis[S]==N)return Maxflow-tmp;
}
}
if(--GAP[dis[x]]==0)dis[S]=N;
else GAP[++dis[x]]++;
return Maxflow-tmp;
}
int SAP(){
memset(GAP,0,sizeof(GAP));
memset(dis,0,sizeof(dis));
GAP[0]=N;
long long Ans=0;
while(dis[S]<N)Ans+=SAP(S,1<<30);
return Ans;
}
int n,k;
void Init(){
n=Getint();k=Getint();
S=0,T=4*n+1,N=T+1;
for(int i=1;i<=n;i++){
string s;
cin>>s;
for(int j=1;j<=n;j++)
Map[i][j]=s[j-1]=='Y';
}
}
int main(){
Init();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(Map[i][j])
AddEdge(i,j+n*3,1);
else
AddEdge(i+n,j+n*2,1);
for(int i=1;i<=n;i++)AddEdge(i,i+n,k);
for(int i=1;i<=n;i++)AddEdge(i+n*2,i+n*3,k);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)AddEdge(S,j,1);
for(int j=1;j<=n;j++)AddEdge(j+n*3,T,1);
int t;
if(SAP()!=n){
cout<<i-1;
return 0;
}
}
cout<<n;
return 0;
}