【最大流】BZOJ1305-[CQOI2009]dance跳舞
2016-08-09 22:04
441 查看
【题目大意】
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
【思路】
假设当前有a首舞曲。
把每个人拆成两个点,从“喜欢”到“不喜欢”连一条容量为k的边。从S往“男孩喜欢”连一条容量为a的边,从“女孩喜欢”往T连一条容量为a的边。
然后对于每对男孩女孩,如果不喜欢,则从“男孩不喜欢”到“女孩不喜欢”连一条容量为1的边,否则从“男孩喜欢”到“女孩喜欢”连一条容量为1的边。
为什么这个是正确的呢?这样相当于喜欢的人之间限制住了至多跳一首,而最多和k个不喜欢的人跳舞。画图感受一下就好了。
如果这a首舞曲都能用到,那么这个网络流应该是满流的。
所以二分答案。
注意很重要的两点:
①二分最后ub还要单独判断一下。
②不要忘了每次E的容量会被修改,所以暂存到rE每次重新回到原始状态。
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
【思路】
假设当前有a首舞曲。
把每个人拆成两个点,从“喜欢”到“不喜欢”连一条容量为k的边。从S往“男孩喜欢”连一条容量为a的边,从“女孩喜欢”往T连一条容量为a的边。
然后对于每对男孩女孩,如果不喜欢,则从“男孩不喜欢”到“女孩不喜欢”连一条容量为1的边,否则从“男孩喜欢”到“女孩喜欢”连一条容量为1的边。
为什么这个是正确的呢?这样相当于喜欢的人之间限制住了至多跳一首,而最多和k个不喜欢的人跳舞。画图感受一下就好了。
如果这a首舞曲都能用到,那么这个网络流应该是满流的。
所以二分答案。
注意很重要的两点:
①二分最后ub还要单独判断一下。
②不要忘了每次E的容量会被修改,所以暂存到rE每次重新回到原始状态。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> #define INF 0x7fffffff #define S 0 #define T 4*n+1 using namespace std; struct node { int to,pos,cap; }; const int MAXN=50+5; int n,k; vector<node> E[MAXN*4+2]; vector<node> tmpE[MAXN*4+2]; int dis[MAXN*4+2]; void addedge(int u,int v,int w) { tmpE[u].push_back((node){v,tmpE[v].size(),w}); tmpE[v].push_back((node){u,tmpE[u].size()-1,0}); E[u].push_back((node){v,E[v].size(),w}); E[v].push_back((node){u,E[u].size()-1,0}); } bool bfs() { memset(dis,-1,sizeof(dis)); queue<int> que; while (!que.empty()) que.pop(); que.push(S); dis[S]=0; while (!que.empty()) { int head=que.front();que.pop(); if (head==T) return true; //首次抵达T即可返回,不需要整张图全部分层 for (int i=0;i<E[head].size();i++) { node tmp=E[head][i]; if (dis[tmp.to]==-1 && tmp.cap) { dis[tmp.to]=dis[head]+1; que.push(tmp.to); } } } return false; } int dfs(int s,int e,int f) { if (s==e) return f; int ret=0; for (int i=0;i<E[s].size();i++) { node &tmp=E[s][i]; if (dis[tmp.to]==dis[s]+1 && tmp.cap) { int delta=dfs(tmp.to,e,min(f,tmp.cap)); if (delta>0) { tmp.cap-=delta; E[tmp.to][tmp.pos].cap+=delta; f-=delta; ret+=delta; if (f==0) return ret; } else dis[tmp.to]=-1; } } return ret; } int dinic() { int flow=0; while (bfs()) { int f=dfs(S,T,INF); if (f) flow+=f;else break; } return flow; } void init() { scanf("%d%d",&n,&k); //0 源点 //1~n 男性喜欢 //n+1~2n 男性不喜欢 //2n+1~3n 女性不喜欢 //3n+1~4n 女性喜欢 //4n+1 汇点 for (int i=1;i<=n;i++) addedge(i,i+n,k); for (int i=2*n+1;i<=3*n;i++) addedge(i,i+n,k); for (int i=1;i<=n;i++) { char str[MAXN]; scanf("%s",str+1); for (int j=1;j<=n;j++) { if (str[j]=='Y') addedge(i,3*n+j,1); else addedge(n+i,2*n+j,1); } } for (int i=1;i<=n;i++) addedge(S,i,0); for (int i=3*n+1;i<=4*n;i++) addedge(i,T,0); } void solve() { int lb=0,ub=n; while (lb+1<ub) { for (int i=S;i<=T;i++) for (int j=0;j<E[i].size();j++) E[i][j]=tmpE[i][j]; int mid=(lb+ub)>>1; for (int i=0;i<n;i++) E[S][i].cap=mid; for (int i=3*n+1;i<=4*n;i++) E[i][E[i].size()-1].cap=mid; int d=dinic(); if (d==mid*n) lb=mid;else ub=mid; } for (int i=S;i<=T;i++) for (int j=0;j<E[i].size();j++) E[i][j]=tmpE[i][j]; for (int i=0;i<n;i++) E[S][i].cap=ub; for (int i=3*n+1;i<=4*n;i++) E[i][E[i].size()-1].cap=ub; int d=dinic(); printf("%d",(d==ub*n)?ub:lb); } int main() { init(); solve(); return 0; }
相关文章推荐
- bzoj1305 [CQOI2009]dance跳舞 最大流 二分
- 【bzoj1305】[CQOI2009]dance跳舞 最大流
- BZOJ1305 [CQOI2009]dance跳舞 最大流+二分
- bzoj 1305: [CQOI2009]dance跳舞(二分+最大流)
- 【二分+最大流Dinic】BZOJ1305(CQOI2009)[dance跳舞]题解
- BZOJ 1305: [CQOI2009]dance跳舞( 最大流 )
- 【二分答案】【最大流】bzoj1305 [CQOI2009]dance跳舞
- BZOJ 1305: [CQOI2009]dance跳舞 最大流
- BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流
- 【bzoj1305】[CQOI2009]dance跳舞 最大流+二分答案
- 【二分+最大流】BZOJ1305 [CQOI2009]dance跳舞
- bzoj1305 [CQOI2009]dance跳舞(二分答案+最大流判是否满流)
- BZOJ 1305: [CQOI2009]dance跳舞 多重匹配,网络最大流
- 【BZOJ1305】[CQOI2009]dance跳舞【最大流】【二分】
- BZOJ 1305: [CQOI2009]dance跳舞 二分+最大流
- BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流
- [BZOJ1305][CQOI2009]dance跳舞(枚举二分+最大流)
- bzoj1305: [CQOI2009]dance跳舞
- BZOJ1305 [CQOI2009]dance跳舞 【网络流】
- BZOJ 1305 [CQOI2009]dance跳舞(二分+网络流)