POJ2289 Jamie's Contact Groups(二分图多重匹配)

题意:

给定一个规模为n的名单,要将名单中的人归到m个组中,给出每个人可能的分组号,需要确定一种分配方案,使得最大规模的组最小。

思路:

二分图多重匹配

如果所到的组没满,就去那个组

如果满了,就从那个组里踢出一个

如果能踢出来,就把那个踢出来,把当前的放进去

如果所有能到的组都踢不出来,就不对了

至于那个最大规模的具体值,二分一下就OK了

/* ***********************************************
Author        :devil
Created Time  :2016/5/17 17:56:52
************************************************ */
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
using namespace std;
const int N=1010;
const int M=510;
int n,m,mid,x;
char s[20];
bool vis[M];
vector<int>eg[N],isin[M];
bool Find(int u)
{
    for(int i=0;i<eg[u].size();i++)
    {
        int v=eg[u][i];
        if(!vis[v])
        {
            vis[v]=1;
            if(isin[v].size()<mid)
            {
                isin[v].push_back(u);
                return 1;
            }
            for(int j=0;j<isin[v].size();j++)
            {
                if(Find(isin[v][j]))
                {
                    isin[v][j]=u;
                    return 1;
                }
            }
        }
    }
    return 0;
}
bool maxmatch()
{
    for(int i=0;i<m;i++)
        isin[i].clear();
    for(int i=0;i<n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(!Find(i)) return 0;
    }
    return 1;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)&&(n+m))
    {
        for(int i=0;i<n;i++)
            eg[i].clear();
        for(int i=0;i<n;i++)
        {
            scanf("%s",s);
            while(scanf("%d",&x)==1)
            {
                eg[i].push_back(x);
                if(getchar()=='
') break;
            }
        }
        int l=0,r=n;
        while(l<r)
        {
            mid=(l+r)>>1;
            if(maxmatch()) r=mid;
            else l=mid+1;
        }
        printf("%d
",r);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/d-e-v-i-l/p/5502614.html