hdu3081 Marriage Match II

题目大意就是有n对男女,玩儿结婚游戏,要求就是开始每个女生心目中都会有几个心仪的男生,同时呢,好友(girl)心仪的男生也是可以选做自己的boyfriend。每一轮游戏男女配对(只和心仪的)且不于之前配对过的配对,问最多可以玩儿几轮这样的游戏。

男女配对显然是二分图,然后就是二分次数k,k必然是大于1而小于n+1的。

/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2015
File Name   :
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
typedef pair<ii,int> iii;
const double eps = 1e-10;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int N = 110;
int g[N][N];
int n, m, f;
int F[N];
int Find(int x) {return F[x] == -1?x:F[x] = Find(F[x]);}
void input() {
	memset(g, 0,sizeof g);
	scanf("%d%d%d",&n,&m,&f);
	int u, v;
	for (int i = 1;i <= m;++i) {
		scanf("%d%d",&u,&v);
		g[u][v] = 1;
	}
	memset(F, -1,sizeof F);
	for (int i = 1;i <= f;++i) {
		scanf("%d%d",&u,&v);
		int t1 = Find(u),t2 = Find(v);
		if (t1 != t2) F[t1] = t2;
	}
	for (int i = 1;i <= n;++i) {
		for (int j = 1;j <= n;++j) {
			int t1 = Find(i),t2 = Find(j);
			if (t1 == t2) {
				for (int k = 1;k <= n;++k)
					g[i][k] |= g[j][k];
			}
		}
	}
}
int head[N*3], pnt[N*1000], nxt[N*1000], cap[N*1000], flow[N*1000];
int cnt;
int cur[N*3];
int dis[N*3];
void addedge(int u,int v,int can) {
	pnt[cnt] = v,cap[cnt] = can, flow[cnt] = 0;
	nxt[cnt] = head[u], head[u] = cnt++;

	pnt[cnt] = u,cap[cnt] = 0,flow[cnt] = 0;
	nxt[cnt] = head[v], head[v] = cnt++;
}
bool bfs(int s,int t) {
	queue<int> que;
	que.push(s);
	memset(dis, -1,sizeof dis);
	dis[s] = 0;
	while(!que.empty()) {
		int u = que.front();
		que.pop();
		for (int i = head[u];i!=-1;i = nxt[i]) {
			if (dis[pnt[i]] == -1 && cap[i] > flow[i]) {
				dis[pnt[i]] = dis[u] + 1;
				que.push(pnt[i]);
			}
		}
	}
	return dis[t] != -1;
}
int dfs(int u,int a,int t) {
	if (u == t || a == 0) return a;
	int sum = 0;
	for (int &i = cur[u];~i;i = nxt[i]) {
		int v = pnt[i];
		int f;
		if (dis[v] == dis[u] + 1 && (f = dfs(v, min(a, cap[i] - flow[i]), t)) > 0) {
			sum += f;
			flow[i] += f;
			flow[i^1] -= f;
			a -= f;
			if (a == 0) break;
		}
	}
	return sum;
}
int MaxFlow(int s,int t) {
	int sum = 0;
	while(bfs(s, t)) {
		memcpy(cur, head, sizeof head);
		sum += dfs(s, INF, t);
	}
	return sum;
}
void getmap(int mid) {
	memset(head, -1,sizeof head);
	cnt = 0;
	int s = 0, t = n*2+1;
	for (int i = 1;i <= n;++i) {
		addedge(s, i, mid);
		addedge(i + n, t, mid);
		for (int j = 1;j <= n;++j) {
			if (g[i][j]) addedge(i, j+n, 1);
		}
	}
}
int main()
{	
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	int t;
	scanf("%d",&t);
	while(t--) {
		input();
		int low = 1,high = n + 1;
		int ans = -1;
		while(low < high) {
			int mid = (low + high) / 2;
			getmap(mid);
			int tmp = MaxFlow(0,n*2+1);
			if (tmp == n*mid) {
				low = mid + 1;
			}else high = mid;
		}
		printf("%d\n", low - 1);
	}
	return 0;
}


你可能感兴趣的:(二分,二分图)