BZOJ1305 [CQOI2009]dance跳舞 【网络流】
1305: [CQOI2009]dance跳舞
Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 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
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; }