N - Marriage Match II - HDU 3081(最大流)
题目大意:有一些男孩和女孩玩一个游戏,每个女孩都可以挑一个男孩来进行这个游戏(所有人都要参加),女孩只会挑选她喜欢的男孩,并且她们认为她们朋友喜欢的男孩她们也是喜欢的(朋友的男朋友也是我的男朋友???),而且她们遵循朋友的朋友也是朋友的原则,问她们最多可以玩几轮游戏(每轮要选择的人不能和以前选择的相同)。
分析:朋友关系很明显可以使用并查集找出来每个女孩可以连接的男孩,因为要求的是最多能进行多少轮游戏,也就是在这x轮游戏中每个女孩换了x不同的男孩,每个男孩也换了x个不同的女孩,如果源点和女孩相连,汇点和男孩相连,那么流量一定是N*x,可以使用二分来查找最大的x。
下面是AC代码。
=========================================================================================================================
#include<stdio.h> #include<string.h> #include<queue> #include<stack> #include<vector> using namespace std; const int MAXN = 207; const int oo = 1e9+7; int G[MAXN][MAXN], Layer[MAXN], N, M; int girl[MAXN*MAXN], boy[MAXN*MAXN], father[MAXN]; vector<int>love[MAXN]; int Find(int x) { if(father[x] != x) father[x] = Find(father[x]); return father[x]; } void InIt() { for(int i=1; i<=N; i++) { father[i] = i; love[i].clear(); } } void BuidGraph(int flow, int start, int End) { memset(G, 0, sizeof(G)); for(int i=1; i<=N; i++) {///源点和女孩相连,汇点和男孩相连,流量是flow G[start][i] = flow; G[i+N][End] = flow; int u = Find(i);///注意别用father[i] int len = love[u].size(); for(int j=0; j<len; j++) {///女孩和男孩之间的流量是1 G[i][love[u][j]] = 1; } } } bool BFS(int start, int End) { memset(Layer, 0, sizeof(Layer)); queue<int> Q; Q.push(start); Layer[start] = 1; while(Q.size()) { int u = Q.front();Q.pop(); if(u == End)return true; for(int v=1; v<=End; v++) { if(Layer[v]==false && G[u][v]) { Layer[v] = Layer[u] + 1; Q.push(v); } } } return false; } int DFS(int u, int MaxFlow, int End) { if(u == End)return MaxFlow; int uflow = 0; for(int v=1; v<=End; v++) { if(Layer[v]==Layer[u]+1 && G[u][v]) { int flow = min(MaxFlow-uflow, G[u][v]); flow = DFS(v, flow, End); G[u][v] -= flow; G[v][u] += flow; uflow += flow; if(uflow == MaxFlow) break; } } if(uflow == 0) Layer[u] = 0; return uflow; } int Dinic(int start, int End) { int MaxFlow = 0; while(BFS(start, End) == true) MaxFlow += DFS(start, oo, End); return MaxFlow; } int main() { int T; scanf("%d", &T); while(T--) { int i, F, u, v; scanf("%d%d%d", &N, &M, &F); InIt(); for(i=1; i<=M; i++) scanf("%d%d", &girl[i], &boy[i]); for(i=1; i<=F; i++) {///用并查集合并朋友关系 scanf("%d%d", &u, &v); u = Find(u); v = Find(v); if(u != v) father[u] = v; } for(i=1; i<=M; i++) {///把相同的朋友的男朋友全部都连接到根节点上,男生的区间N~2*N u = Find(girl[i]); love[u].push_back(boy[i]+N); } int start=N*2+1, End = start+1; int left = 0, right = N, ans=0; while(left <= right) { int Mid = (left+right)>>1; BuidGraph(Mid, start, End); int MaxFlow = Dinic(start, End); if(MaxFlow == Mid*N) { left = Mid + 1; ans = Mid; } else right = Mid - 1; } printf("%d\n", ans); } return 0; }