bzoj1305 [CQOI2009]dance跳舞 最大流 二分
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; }