bzoj1305 [CQOI2009]dance跳舞 最大流 二分
来源:互联网 发布:3d头像制作软件 编辑:程序博客网 时间:2024/04/30 06:58
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;}
0 0
- bzoj1305 [CQOI2009]dance跳舞 最大流 二分
- 【BZOJ1305】[CQOI2009]dance跳舞【最大流】【二分】
- BZOJ1305 [CQOI2009]dance跳舞 最大流+二分
- 【二分+最大流】BZOJ1305 [CQOI2009]dance跳舞
- 【bzoj1305】[CQOI2009]dance跳舞 最大流+二分答案
- [BZOJ1305][CQOI2009]dance跳舞(枚举二分+最大流)
- 【二分+最大流Dinic】BZOJ1305(CQOI2009)[dance跳舞]题解
- 【bzoj1305】[CQOI2009]dance跳舞 最大流
- bzoj1305 [CQOI2009]dance跳舞(二分答案+最大流判是否满流)
- BZOJ1305 [CQOI2009]dance跳舞
- bzoj1305【CQOI2009】dance 跳舞
- bzoj1305[CQOI2009]dance跳舞
- bzoj1305: [CQOI2009]dance跳舞
- bzoj1305 [CQOI2009]dance跳舞
- 【bzoj1305】【CQOI2009】【dance】【跳舞】
- BZOJ1305: [CQOI2009]dance跳舞
- bzoj1305 [CQOI2009]dance跳舞
- bzoj1305[CQOI2009]dance跳舞
- 微信抢红包神器-安卓专享。再也不会错过红包了
- hdu 2156 分数矩阵
- 微软编程题:寻找最小的k个值
- Java 并发:Executors 和线程池
- c#之params参数
- bzoj1305 [CQOI2009]dance跳舞 最大流 二分
- jdk与jre的区别
- 《魔灵保卫者》服务端架构及实现
- 响应者
- 大整数类加减乘除的简单实现——C++
- 2015年在微信热传的100+经典技术文章-读书笔记
- Android数据存储方式之SQLite(1、SQLiteDatabase)
- JS获取时间差
- 基本概念