二分多重匹配模板

以POJ 2289 为例。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <map>
#include <queue>
#include <stack>
using namespace std;

const int MAXN = 1010;
const int MAXM = 1010*510;

struct Edge
{
	int v;
	int next;
}edge[MAXM];

int nx, ny; //nx为左集合数目,ny为右集合数目 
int cnt;
int limit; //表示每个右集合顶点最多匹配的左集合顶点个数,也可能为数组 

int first[1010];
bool vis[1010]; //寻找增广路径时的标记数组 
int vylink[1010]; //表示右集合i顶点分配到左集合的顶点数 
int ylink[510][1010]; //表示与右集合i顶点匹配的第j个元素 
 
void init()
{
	cnt = 0;
	memset(first, -1, sizeof(first));
}

void read_graph(int u, int v)
{
	edge[cnt].v = v;
	edge[cnt].next = first[u], first[u] = cnt++;
}

int find(int u)
{
	int i, j;
    for(int e = first[u]; e != -1; e = edge[e].next)
    {
		i = edge[e].v;
        if(!vis[i])
        {
            vis[i] = 1;
            if(vylink[i] < limit)
            {
                ylink[i][vylink[i]++] = u;
                return 1;
            }
            for(j = 0; j < vylink[i]; j++)
                if(find(ylink[i][j]))
                {
                    ylink[i][j] = u;
                    return 1;
                }
        }
	}
	return 0;
}
 
 bool MulMatch()
 {
     memset(vylink, 0, sizeof(vylink));
     for(int i = 0; i < nx; i++)
     {
         memset(vis , 0, sizeof(vis));
         if(!find(i)) return 0;
     }
     return 1;
 }

void BSearch()
{
	int x = 0, y = nx;
	while(x <= y)
	{
		limit = (x+y)/2;
		if(MulMatch()) y = limit-1;
		else x = limit+1;
	}
	printf("%d\n", x);
}

void read_case()
{
	init();
	char str[3020];
	for(int i = 0; i < nx; i++)
	{
		gets(str);
		for(int j = 0; j < strlen(str); j++) if(isdigit(str[j]))
		{ // for(int j = 0; str[j]; j++) 报错了,scanf("%s", str)才能用 
			int v = 0;
			while(isdigit(str[j]))
			{
				v = v*10 + str[j++]-'0';
			}
			read_graph(i, v);
		}
	}
}

void solve()
{
	read_case();
	BSearch();
}

int main()
{
	while(scanf("%d%d%*c", &nx, &ny) && (nx || ny))
	{
		solve();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值