hdu1669杰米的电话联系人(多重匹配)

博客介绍了如何解决杰米的电话联系人分组问题,将其转化为一个多重匹配问题,并利用二分搜索法降低搜索空间。具体算法包括初始化匹配、二分搜索、检查增广路径等步骤,旨在找到最大分组中规模最小的解决方案。
摘要由CSDN通过智能技术生成

题意:杰米想给手机里面的联系人分组,问最大分组中的规模最小,给了每个联系人可能所在组的编号;

思路:显然是一个多重匹配问题,x(联系人),y(组编号);一般来说,对最大限制的选取(这里是“最大分组中的规模最小”)通常采用二分搜索来降低搜索空间;具体搜索做法和Hungary()差不多,变的就是cy[maxn]变成cy[maxn][maxn],同时用num[i]来表示与y[i]匹配的x[...]的数目,cy[i][j]表示与y[i]匹配的第j个元素(x);

算法流程入下:

(1)从G = (X,Y;E)中选取一个初始匹配M。设置初始搜索的上限和下限(二分值)。

(2)对最大限制n进行二分搜索。知道下限值大于上限值。

(3)若X中的点全部被M匹配,说明可以达到一个多重匹配,转至步骤(2);否则若与元素y[i]匹配的数目num[i] < n,则将x[i]与y[i]进行匹配。

(4)如果与y[i]匹配的元素已经达到上限,那么在与y[i]匹配的元素中选者一个元素,检查是否能找到一条增广路径,如果能,则让出位置,让x[i]与y[i]匹配。转至步骤(2)。

/*****************************************
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 <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
using namespace std;
#define MEM(a,b) memset(a,b,sizeof a)
#define pk push_back
template<class T> inline T Get_Max(const T&a,const T&b){return a < b?b:a;}
template<class T> inline T Get_Min(const T&a,const T&b){return a < b?a:b;}
typedef long long ll;
typedef pair<int,int> ii;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1010;
const int maxm = 510;
int uN,vN;
int g[maxn][maxm];
int link[maxm][maxm];
bool vis[maxm];
int num[maxm];
bool dfs(int u){
	for (int v = 0;v < vN;v++){
		if (g[u][v] && !vis[v]){
			vis[v] = true;
			if (link[v][0] < num[v]){
				link[v][++link[v][0]] = u;
				return true;
			}
			for (int i = 1;i <= num[0];i++){
				if (dfs(link[v][i])){
					link[v][i] = u;
					return true;
				}
			}
		}
	}
	return false;
}
int Hungary(){
	int ret = 0;
	for (int i = 0;i < vN;i++)
		link[i][0] = 0;
	for (int u = 0;u < uN;u++){
		MEM(vis, false);
		if (dfs(u)) ret++;
	}
	return ret;
}

char str[10000];
char name[100];

int main()
{	
	// ios::sync_with_stdio(false);
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	while(scanf("%d%d",&uN,&vN) == 2){
		if (uN == 0 && vN == 0) break;
		MEM(g, 0);
		gets(str);
		// fgets(str,10000,stdin);
		for (int i = 0;i < uN;i++){
			gets(str);
			// fgets(str,10000,stdin);
			int v;
			char *p = strtok(str," ");
			sscanf(p,"%s",name);
			p = strtok(NULL," ");
			while(p != NULL){
				sscanf(p,"%d",&v);
				g[i][v] = 1;
				p = strtok(NULL," ");
			}
		}
		int ans;
		int l = 1,r = uN;
		while(l <= r){
			int mid = (l + r) >> 1;
			for (int i = 0;i < vN;i++)
				num[i] = mid;
			if (Hungary() >= uN){
				ans = mid;
				r = mid - 1;
			}
			else l = mid + 1;
		}
		printf("%d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值