一次舞會有n個男孩和n個女孩。每首曲子開始時,所有男孩和女孩恰好配成n對跳交誼舞。每個男孩都不會和同一個女孩跳兩首(或更多)舞曲。有一些男孩女孩相互喜歡,而其他相互不喜歡(不會“單向喜歡”)。每個男孩最多只願意和k個不喜歡的女孩跳舞,而每個女孩也最多只願意和k個不喜歡的男孩跳舞。給出每對男孩女孩是否相互喜歡的信息,舞會最多能有幾首舞曲?n<=50.
看到數據範圍可以考慮網絡流建模.
把每個男孩和女孩拆成兩個點,分別表示喜歡和不喜歡.
設每次二分的答案是x.
源點向每個男孩的喜歡點連一條x的邊,每個女孩的喜歡點向匯點連一條x的邊
考慮每一對是否喜歡
如果喜歡就在兩人喜歡點之間連1的邊,
反之在不喜歡點之間連1的邊。
最後在從男孩的喜歡向不喜歡,女孩的不喜歡向喜歡連K的邊.
這樣就解決了所有題中的限制條件,跑最大流即可.
#include<bits/stdc++.h>
#define LL long long
#define clr(x,i) memset(x,i,sizeof(x))
using namespace std;
const int N=202,INF=9999999;
struct Edge{
int to,nex,cap;
}edge[N*N*2];
int n,K,tot,head[N],cur[N];
inline void Add(int u,int v,int c)
{
edge[++tot].to=v;edge[tot].nex=head[u];edge[tot].cap=c;head[u]=tot;
edge[++tot].to=u;edge[tot].nex=head[v];edge[tot].cap=0;head[v]=tot;
}
char str[N][N];
int s,t,que[N*N*4],dist[N*4];
bool bfs()
{
clr(dist,60);
dist[s]=0;que[1]=s;
int l=0,r=1;
while(l<r)
{
int u=que[++l];
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].to,cap=edge[i].cap;
if(dist[v]>INF&&cap>0)
dist[v]=dist[u]+1,que[++r]=v;
}
}
return dist[t]<INF;
}
int dfs(int u,int maxf)
{
if(u==t)return maxf;
for(int i=cur[u];i;i=edge[i].nex){
cur[u]=i;//當前弧
int v=edge[i].to,cap=edge[i].cap;
if(dist[v]==dist[u]+1&&cap>0){
int flow=dfs(v,min(maxf,cap));
if(flow){
edge[i].cap-=flow;
edge[i^1].cap+=flow;
return flow;
}
}
}
return 0;///這個經常忘...
}
int dinic()
{
int ret=0,flow;
while(bfs()){
for(int i=s;i<=t;i++)cur[i]=head[i];
while(flow=dfs(s,INF))
ret+=flow;
}
return ret;
}
void work(int now)
{
tot=1;clr(head,0);
s=0;t=n*4+1;
for(int i=1;i<=n;i++){
Add(s,i,now);Add(i,n+i,K);
Add(n*2+i,t,now);Add(n*3+i,n*2+i,K);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(str[i][j]=='Y')
Add(i,n*2+j,1);
else
Add(n+i,n*3+j,1);
}
int main()
{
//freopen("bzoj1305.in","r",stdin);
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++)
scanf("%s",str[i]+1);
int l=0,r=n,mid,ans=0;
while(l<=r){
mid=(l+r)>>1;
work(mid);
if(dinic()>=mid*n)
l=mid+1,ans=mid;
else
r=mid-1;
}
printf("%d",ans);
return 0;
}
這個當前弧優化真的是神級優化...
本地跑出來也是將近100倍的差距...
orz..