Jamie's Contact Groups

二分 + 多值匹配 

思路:一对多的二分图的多重匹配。二分图的多重匹配算法的实现类似于匈牙利算法,对于集合C中的元素xi,找到一个与其相连的元素yi后,检查匈牙利算法的两个条件是否成立,若yi未被匹配,则将
xi,yi匹配。否则,如果与yi匹配的元素已经达到上限,那么在所有与yi匹配的元素中选择一个元素,检查是否能找到一条增广路径,如果能,则让出位置,让xi与yi匹配。
二分求出limit,知道找到可以构成多重匹配的最小限制limit,在main函数中二分搜索。
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

using namespace std;
#define MAXN 1111
int cx[MAXN][MAXN];
bool gra[MAXN][MAXN], vis[MAXN];
int n, m, limit;

bool dfs( int u )
{
    for( int v = 0; v < m; v++)
    {
        if(gra[u][v] && !vis[v])
        {
            vis[v] = 1;
            if(cx[v][0] < limit)
            {
                cx[v][++cx[v][0]] = u;
                return true;
            }
            for( int i = 1; i <= cx[v][0]; i++)
              if(dfs(cx[v][i]))
              {
                  cx[v][i] = u;
                  return true;
              }

        }
    }
    return false;
}
bool check( )
{
    int res = 0;
    for( int i = 0; i < m; i++)
         cx[i][0] = 0;
    for( int i = 0; i < n; i++)
    {
        memset(vis, 0, sizeof(vis));
        if(!dfs(i)) return false;
    }
    return true;
}

void solve( )
{
    int l, r;
    l = 0, r = n;
    int ans = 0;
    while(l < r)
    {
        limit = ( l + r ) >> 1;
        if(check())
            r = limit;
        else
            l = limit + 1;
    }
    printf("%d\n",r);
}

int main()
{
    char str[2100];
    while(scanf("%d %d",&n, &m) != EOF &&( n + m))
    {
        memset(gra, 0, sizeof(gra));
        getchar();
        for( int i = 0; i < n; i++)
        {
            gets(str);
            int len  = strlen(str);
            for( int j = 0; j < len; j++)
            {
                if(str[j] >= '0' && str[j] <= '9')
                {
                    int v = 0;
                    while(str[j] >= '0' && str[j] <= '9')
                        {
                            v = v*10 + (str[j] - '0');
                            j++;
                        }
                     gra[i][v] = 1;
                }
            }
        }
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值