poj2289多重二分匹配

来源:互联网 发布:sql 查询数据库大小 编辑:程序博客网 时间:2024/05/16 12:08

poj2289多重二分匹配

  • 题目链接:http://poj.org/problem?id=2289

题目部分

题意:
题目说一个人要给电话簿进行分组,每个人可以分到特定的组(一个人只能进一个组,但供选择的组有多个)。要你计算分到人数最多的那个组,最小有几个人

输入数据
多组测试数据,每组测试数据先输入2个数,第一个数是人数n,第二个数是组数m,如果这两个数输入的是0 0表示程序结束。
接下来n行会结束人的信息
名字 可以进入的组(这里没有说明有几组所有输入的时候要做好处理)
这里组是从0开始计算的。

输出数据
最多人数的那个组中最小人数。

样例解析:
3 2
John 0 1
Rose 1
Mary 1
5 4
ACM 1 2 3
ICPC 0 1
Asian 0 2 3
Regional 1 2
ShangHai 0 2
0 0
第一组数据:
有3个人,2个组
John 可以进入 0、1组
Rose 可以进入1组
Mary 可以进入1组
第二组数据:
ACM 可以进入1、2、3组
ICPC 可以进入0、1组
Asian 可以进入0、2、3组
Regional 可以进入1、2组
ShangHai 可以进入0、2组
第一组输出:
可以3个人都进1组,这样最大人数的组的人数是3
可以John进0组,剩下2个人进1组,这样最大人数的组人数是2
所以输出结果是2。(就写一组了,( ⊙ o ⊙ )懒了)

思路部分

要看二分匹配的可以看这个博客:
http://blog.csdn.net/dark_scope/article/details/8880547
(前面一篇博客就推过)
这题跟二分匹配的差别就在于右边可以连接多个左边,所以把二分匹配中保存右边的连接数组改成二维数组就可以了,你可以另外拿一个数组存放了几个数,我这边是用这个二维数组的connect[i][0]来存放第i行存了几个数。
这样要找最小我们就可以遍历所有可能,也就是最大的组的人数可能,从1到n(所有人都进到一个组),这里用二分法搜索加速
像第一组测试数据,假设最少3人进行二分多重匹配,所有人都匹配上那么这种情况是可以的,我们就缩小范围。
2个人是最少的这样所有人还是都匹配上了,继续缩小,1个人最少,这样有人没有匹配上,那么最少的人数就是2了。

代码部分

#define _CRT_SECURE_NO_DEPRECATE#include<iostream>#include<cstring>#include<algorithm>#include<fstream>#include<math.h>#include<algorithm>#include<stack>#include<queue>using namespace std;//fstream fin("1.txt");//streambuf *buf = cin.rdbuf(fin.rdbuf());//用于重定项输入改成,把cin当成fin//FILE *buf = freopen("1.txt", "a+", stdin);//用于重定项文件输入,scanf也能用(这里代码的第一行必须加上才能用这句话)const int inf = 1 << 29;const int MAXN = 1010;int n, m;int limit;int map[MAXN][MAXN];int connect[MAXN][MAXN];//每行的0保存这一行存放了几个数bool vis[MAXN];bool find(int p){    for (int i = 1; i <= m; i++)    {        if (map[p][i] && !vis[i])        {            vis[i] = true;            if (connect[i][0] < limit)            {                connect[i][0]++;                connect[i][connect[i][0]] = p;                return true;            }            for (int j = 1; j <= connect[i][0]; j++)            {                if (find(connect[i][j]))                {                    connect[i][j] = p;                    return true;                }            }        }    }    return false;}bool judge(){    memset(connect, 0, sizeof(connect));    for (int i = 1; i <= n; i++)    {        memset(vis, 0, sizeof(vis));        if (!find(i))//如果返回false,就说明找不到合适的匹配,那么这个Limit就不行直接退出<因为每个人都有被分配到组里面            return false;    }    return true;}int main(){    char str[20];    int a;    int left, right;    while (cin >> n >> m && (n + m))    {        memset(map, 0, sizeof(map));        for (int i = 1; i <= n; i++)        {            scanf_s("%s", str, 20);            while (true)            {                scanf_s("%d", &a);                map[i][a + 1] = 1;                if (getchar() == '\n') break;            }        }        left = 0;        right = n + 1;        int result;        while (left <= right)        {            limit = (left + right) >> 1;            if (judge())            {                result = limit;                right = limit - 1;            }            else                left = limit + 1;        }        cout << result << endl;    }    return 0;}
0 0
原创粉丝点击