bzoj1305 [CQOI2009]dance跳舞
题意:一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。 有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。 给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?n<=50
题解:拆点= =
二分答案(枚举也可以orz)
然后就变成判定性问题啦
然后我们看到这是一个二分图
左边代表男孩 右边代表女孩
我们可以愉快的拆点
每个节点拆成3个点 我们依次叫它node1,2,3
二分图左边的每个节点的前两个分点(node1,2)连的边代表最多跳的舞曲数(二分出来的x)
后两个分点(node2,3)连的边代表最多和不喜欢的人跳舞次数(k)
二分图右边的点反过来
然后总源点和左边的所有node1连inf
又边的所有node3和总汇点连inf
左边node3和不喜欢的人的node1连1
左边node2和喜欢的人的node2连1
然后跑最大流 flow==x*n 代表是可行解
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
bool bfs();int dfs(int,int);int dinic();
queue<int>Q;
const int inf=1<<30,Maxn=400,Maxm=400*400;
struct E{int to,cap,flow,nxt;}edge[Maxm*2];
int tot=2,s,t,n,k;
int idx[Maxn],a[Maxm],cur[Maxn],dis[Maxn];
char map[Maxn][Maxn];bool vis[Maxn];
void addedge(int from,int to,int c){
edge[tot].to=to;edge[tot].cap=c;edge[tot].flow=0;edge[tot].nxt=idx[from];idx[from]=tot++;
}
void add(int from,int to,int cap){addedge(from,to,cap);addedge(to,from,0);}
void init(){
scanf("%d%d\n",&n,&k);
for(int i=1;i<=n;i++)
scanf("%s\n",map[i]+1);
}
int node1(char c,int i){return c=='l'?i:3*n+i;}
int node2(char c,int i){return c=='l'?i+n:4*n+i;}
int node3(char c,int i){return c=='l'?i+2*n:5*n+i;}
void build(int x){
memset(edge,0,sizeof(E));
memset(idx,0,sizeof(idx));tot=2;
s=n*6+1,t=n*6+2;
for(int i=1;i<=n;i++)
add(s,node1('l',i),inf),
add(node3('r',i),t,inf);
for(int i=1;i<=n;i++){
add(node1('l',i),node2('l',i),x);
add(node2('l',i),node3('l',i),k);
add(node2('r',i),node3('r',i),x);
add(node1('r',i),node2('r',i),k);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(map[i][j]=='Y') add(node2('l',i),node2('r',j),1);
else add(node3('l',i),node1('r',j),1);
}
//printf("\n");
}
bool judge(int x){return dinic()>=x*n?1:0;}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
init();int l=0,r=n+1,i;
/*for(i=1;i<=n;i++){ build(i); if(!judge(i)) break; } printf("%d\n",i-1);*/
while(l<r){
int mid=(l+r)/2;
//printf("%d\n",mid);
build(mid);
if(judge(mid)) l=mid+1;
else r=mid;
}
printf("%d\n",l-1);
return 0;
}
bool bfs(){
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
Q.push(s);vis[s]=1;
while(!Q.empty()){
int x=Q.front();Q.pop();
for(int i=idx[x];i;i=edge[i].nxt){
E e=edge[i];
if(!vis[e.to] && e.cap>e.flow)
vis[e.to]=1,Q.push(e.to),dis[e.to]=dis[x]+1;
}
}
//for(int i=0;i<=T;i++) printf("%d ",dis[i]);
return vis[t];
}
int dfs(int x,int a){
int flow=0,f;
if(x==t || a==0) return a;
for(int& i=cur[x];i;i=edge[i].nxt){
E e=edge[i];
if(dis[x]+1==dis[e.to]){
f=dfs(e.to,min(a,e.cap-e.flow));
if(f>0){
edge[i].flow+=f;
edge[i^1].flow-=f;
flow+=f;a-=f;if(!a) break;
}
}
}
return flow;
}
int dinic(){
int flow=0;
while(bfs()){
for(int i=1;i<=t;i++) cur[i]=idx[i];
flow+=dfs(s,inf);
}
return flow;
}