【BZOJ1305】dance跳舞
1305: [CQOI2009]dance跳舞
Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 3076 Solved: 1296
[Submit][Status][Discuss]
Description
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
Input
第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为'Y'当且仅当男孩i和女孩j相互喜欢。
Output
仅一个数,即舞曲数目的最大值。
Sample Input
3 0
YYY
YYY
YYY
YYY
YYY
YYY
Sample Output
3
HINT
N<=50 K<=30
Source
Solve:
我真是蠢飞了 先花了一个正解然后觉得自己不对 又删掉了……
事实证明是对的 只需要套个二分就可以了
这个题交给我一件事:bzoj每个int、bool类函数都需要有返回值 不然T的挺挺的
说说题解:首先我们拆点,每个点认为是和他喜欢的或不喜欢的跳舞 喜欢的拆成i,不喜欢的拆成i'
然后i->i'连一条k的边
然后S到每个i(男或女?反正其中一个,然后j是另一种)连一条INF的边,每个j到T连一条INF边
对于[i,j],假如map[i,j]='Y'连边(i,j,1),否则连边(i',j',1)
最后二分答案 验证一下就好了
/*To The End Of The Galaxy*/ #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<iomanip> #include<stack> #include<map> #include<set> #include<cmath> #define debug(x) cerr<<#x<<"="<<x<<endl #define INF 0x7f7f7f7f #define llINF 0x7fffffffffffll #define P(x,y) (((x-1)*m)+y) using namespace std; typedef pair<int,int> pii; typedef long long ll; inline int init() { int now=0,ju=1;char c;bool flag=false; while(1) { c=getchar(); if(c=='-')ju=-1; else if(c>='0'&&c<='9') { now=now*10+c-'0'; flag=true; } else if(flag)return now*ju; } } inline long long llinit() { long long now=0,ju=1;char c;bool flag=false; while(1) { c=getchar(); if(c=='-')ju=-1; else if(c>='0'&&c<='9') { now=now*10+c-'0'; flag=true; } else if(flag)return now*ju; } } struct edge { int from,to,cap,flow,pre; }Edge[50005]; int head[505],dis[505],cur[505]; bool vis[505]; int n,k,cnt; char tmp[52]; inline void addedge(int from,int to,int cap) { ++cnt; Edge[cnt]=((edge){from,to,cap,0,head[from]}); head[from]=cnt; ++cnt; Edge[cnt]=((edge){to,from,0,0,head[to]}); head[to]=cnt; } int m=2; int S,T; queue<int> q; bool bfs() { int now; while(!q.empty())q.pop(); memset(vis,0,sizeof(vis)); dis[S]=0; q.push(S); while(!q.empty()) { now=q.front();q.pop(); if(now==T)return true; if(vis[now])continue; vis[now]=1; for(int j=head[now];j;j=Edge[j].pre) { if(!vis[Edge[j].to]&&Edge[j].cap>Edge[j].flow) { dis[Edge[j].to]=dis[now]+1; q.push(Edge[j].to); } } } return false; } inline int dfs(int now,int maxflow) { if(now==T||maxflow==0)return maxflow; int &j=cur[now]; int flow=0,f; for(;j;j=Edge[j].pre) { if(dis[Edge[j].to]==dis[now]+1&&(f=dfs(Edge[j].to,min(maxflow,Edge[j].cap-Edge[j].flow)))>0) { flow+=f;maxflow-=f; Edge[j].flow+=f;Edge[((j-1)^1)+1].flow-=f; if(maxflow==0)break; } } return flow; } int dinic() { int ans=0; while(bfs()) { for(register int i=1;i<=T;i++)cur[i]=head[i]; ans+=dfs(S,INF); } return ans; } int le,re; void reset(int x) { for(register int i=1;i<=cnt;i++) { Edge[i].flow=0; } for(register int i=le;i<=re;i++) { if(i&1) { Edge[i].cap=x; } } } int main() { n=init();k=init(); S=(4*n)+1;T=S+1; for(register int i=1;i<=n;i++) { addedge(P(i,1),P(i,2),k); } for(register int i=1;i<=n;i++) { addedge(P(i+n,2),P(i+n,1),k); } for(register int i=1;i<=n;i++) { scanf("%s",tmp+1); for(register int j=1;j<=n;j++) { if(tmp[j]=='Y') { addedge(P(i,1),P(j+n,1),1); } else { addedge(P(i,2),P(j+n,2),1); } } } int l=0,r=n; int ans=0; le=cnt+1; for(register int i=1;i<=n;i++) { addedge(P(i+n,1),T,INF); } for(register int i=1;i<=n;i++) { addedge(S,P(i,1),INF); } re=cnt; int mid; while(l<=r) { mid=((l+r)>>1); reset(mid); if(dinic()>=n*mid) { ans=mid; l=mid+1; } else r=mid-1; } printf("%d\n",ans); return 0; }