BZOJ1305 [CQOI2009]dance跳舞 【网络流】

1305: [CQOI2009]dance跳舞

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 3714  Solved: 1572
[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

Sample Output

3

HINT

N<=50 K<=30


匹配问题,用网络流解决

将每个人拆开成喜欢和不喜欢,分别连边,然后二分向源汇点连边的容量,每次看看是否能满载

具体【我们假设x是喜欢,y是不喜欢,i是男孩,j是女孩】:

①男孩i与女孩j相互喜欢,xi->xj,容量1

②男孩i与女孩j不喜欢,yi->yj,容量1

③xi->yi,容量K

④yj->xj,容量K

二分容量w

⑤S->xi,容量w

⑥xj->T,容量w

每次跑一次最大流看看能够满载即w * N,能说明可以跳至少w次舞

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 605,maxm = 1000005,INF = 1000000000;
inline int RD(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
	return out * flag;
}
char s[55][55];
int N,K,S,T,head[maxn],d[maxn],vis[maxn],nedge = 0,cur[maxn];
struct EDGE{int to,f,next;}edge[maxm];
inline void build(int u,int v,int w){
	edge[nedge] = (EDGE){v,w,head[u]}; head[u] = nedge++;
	edge[nedge] = (EDGE){u,0,head[v]}; head[v] = nedge++;
}
bool bfs(){
	memset(vis,0,sizeof(vis));
	queue<int> q; int u,to;
	q.push(S); vis[S] = true;
	while (!q.empty()){
		u = q.front(); q.pop();
		Redge(u) if (edge[k].f && !vis[to = edge[k].to]){
			d[to] = d[u] + 1; vis[to] = true; q.push(to);
		}
	}
	return vis[T];
}
int dfs(int u,int minf){
	if (u == T || !minf) return minf;
	int flow = 0,f,to;
	if (cur[u] == -2) cur[u] = head[u];
	for (int& k = cur[u]; k != -1; k = edge[k].next)
		if (d[to = edge[k].to] == d[u] + 1 && (f = dfs(to,min(minf,edge[k].f)))){
			edge[k].f -= f; edge[k ^ 1].f += f;
			flow += f; minf -= f;
			if (!minf) break;
		}
	return flow;
}
int maxflow(){
	int flow = 0;
	while (bfs()){
		fill(cur,cur + maxn,-2);
		flow += dfs(S,INF);
	}
	return flow;
}
bool check(int w){
	nedge = 0; memset(head,-1,sizeof(head));
	REP(i,N) build(S,i,w),build(i,i + N,K),build(i + 3 * N,i + 2 * N,K);
	REP(i,N) REP(j,N)
		if (s[i][j] == 'Y') build(i,j + 2 * N,1);
		else build(i + N,j + 3 * N,1);
	REP(i,N) build(i + 2 * N,T,w);
	return maxflow() >= w * N;
}
int main(){
	scanf("%d%d",&N,&K); S = 0; T = 4 * N + 1;
	REP(i,N) scanf("%s",s[i] + 1);
	int L = 0,R = N,mid;
	while (L < R){
		mid = L + R + 1 >> 1;
		if (check(mid)) L = mid;
		else R = mid - 1;
	}
	cout<<L<<endl;
	return 0;
}


posted @ 2017-12-15 18:13  Mychael  阅读(157)  评论(0编辑  收藏  举报