hihoCoder 1393 网络流三·二分图多重匹配(Dinic求二分图最大多重匹配)

#1393 : 网络流三·二分图多重匹配

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

学校的秋季运动会即将开始,为了决定参赛人员,各个班又开始忙碌起来。

小Hi和小Ho作为班上的班干部,统计分配比赛选手的重任也自然交到了他们手上。

已知小Hi和小Ho所在的班级一共有N名学生(包含小Hi和小Ho),编号依次为1..N。

运动会一共有M项不同的比赛,编号为1..M。第i项比赛每个班需要派出m[i]名选手参加。

根据小Hi和小Ho的统计,编号为i的学生表示最多同时参加a[i]项比赛,并且给出他所擅长的b[i]项比赛的编号。

小Hi和小Ho希望将每个学生都安排到他所擅长的比赛项目,以增加夺冠的可能性。同时又要考虑满足每项比赛对人数的要求,当然给一个学生安排的比赛项目也不能超过他愿意参加的比赛项目数量。

根据统计的结果,小Hi和小Ho想知道能否有一个合适的安排,同时满足这些条件。

提示:二分图多重匹配

输入

第1行:1个整数T,表示一共有T(2≤T≤5)组数据,每组数据按如下格式给出:

第1行:2个正整数N,M。1≤N≤100,1≤M≤100。

第2行:M个整数,第i个数表示第i个项目需要的选手数量m[i]。1≤m[i]≤N。

第3..N+2行:若干整数,第i+2行表示编号为i的学生的信息。先是a[i],b[i],接下来b[i]个整数,表示其所擅长的b[i]个项目。1≤a[i]≤M

输出

第1..T行:第i行表示第i组数据能否满足要求,若能够输出"Yes",否则输出"No"。

样例输入
2
4 3
1 2 2
1 2 1 2
2 2 1 3
1 1 2
1 2 2 3
4 3
2 2 2
1 2 1 2
2 2 1 3
1 1 2
1 2 2 3
样例输出
Yes
No

题目链接:hihoCoder 1393

要用网络流做二分图的多重匹配就要知道二分匹配的边的作用,至少先搞懂普通二分匹配是怎么回事

先回想一下二分图的普通最大匹配是如何建图的:源点到$Xi$的容量边其实是用来表示Xi最多可以匹配多少个人;从$Xi$到$Yi$的容量边表示$Xi$是否能与$Yi$匹配;从$Yi$到汇点的容量边表示Yi最多可以被多少个人匹配。显然普通二分图以上容量均为1,那么参照以上的原理,多重匹配就是把最左和最右改一下即可,中间的为什么不用改呢?一个人对于一个项目的作用只有1,不可能达到两个人的效果,因此容量限制还是只有1,话说Dinic比朴素Ford_Fulkerson快了很多……可能是FF写的搓吧(dinic也没好看到哪里去)

最近要期末考了,抓紧时间复习(预习- -|||),基本就不刷题了颓废一下,考完再刷……

代码:

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 210;
const int M = 10200;
struct edge
{
    int to, nxt;
    int cap;
};
edge E[M << 1];
int head[N], tot;
int d[N];

void init()
{
    CLR(head, -1);
    tot = 0;
}
inline void add(int s, int t, int cap)
{
    E[tot].to = t;
    E[tot].cap = cap;
    E[tot].nxt = head[s];
    head[s] = tot++;

    E[tot].to = s;
    E[tot].cap = 0;
    E[tot].nxt = head[t];
    head[t] = tot++;
}
int bfs(int s, int t)
{
    CLR(d, INF);
    d[s] = 0;
    queue<int>Q;
    Q.push(s);
    while (!Q.empty())
    {
        int now = Q.front();
        Q.pop();
        for (int i = head[now]; ~i; i = E[i].nxt)
        {
            int v = E[i].to;
            if (d[v] == INF && E[i].cap > 0)
            {
                d[v] = d[now] + 1;
                if (v == t)
                    return 1;
                Q.push(v);
            }
        }
    }
    return d[t] != INF;
}
int dfs(int s, int t, int f)
{
    if (s == t || !f)
        return f;
    int ret = 0;
    for (int i = head[s]; ~i; i = E[i].nxt)
    {
        int v = E[i].to;
        if (d[v] == d[s] + 1 && E[i].cap > 0)
        {
            int dx = dfs(v, t, min(f, E[i].cap));
            if (dx > 0)
            {
                E[i].cap -= dx;
                E[i ^ 1].cap += dx;
                ret += dx;
                f -= dx;
                if (!f)
                    break;
            }
        }
    }
    if (!ret)
        d[s] = -1;
    return ret;
}
int dinic(int s, int t)
{
    int ret = 0;
    while (bfs(s, t))
        ret += dfs(s, t, INF);
    return ret;
}
int main(void)
{
    int n, m, i, d, k, a, b;
    int tcase;
    scanf("%d", &tcase);
    while (tcase--)
    {
        init();
        int sum = 0;
        scanf("%d%d", &n, &m);
        int S = 0, T = n + m + 1;
        for (i = 1; i <= m; ++i)
        {
            int ned;
            scanf("%d", &ned);
            sum += ned;
            add(n + i, T, ned);
        }
        for (i = 1; i <= n; ++i)
        {
            scanf("%d%d", &a, &b);
            add(S, i, a);
            while (b--)
            {
                scanf("%d", &k);
                add(i, n + k, 1);
            }
        }
        puts(dinic(S, T) == sum ? "Yes" : "No");
    }
    return 0;
}
时间: 2024-10-04 15:48:49

hihoCoder 1393 网络流三·二分图多重匹配(Dinic求二分图最大多重匹配)的相关文章

hihoCoder 1393 网络流三&#183;二分图多重匹配 (网络流学习#3 记录)

题目链接:http://hihocoder.com/problemset/problem/1393 话说我之前一直不知道二分匹配可以用网络流做... #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=205; struct ss{ int v,c,nxt; } e[N*20]; int head[N],tot,vis[N],n,m,a[N],b[N],s

[HihoCoder1393]网络流三&#183;二分图多重匹配

题目大意: 班级有N名学生,运动会有M项不同的比赛,第i项比赛每个班需要派出m_i名选手参加,编号为i的学生最多同时参加给定的b_i项比赛中的任意a_i项比赛.根据统计的结果,想知道能否有一个合适的安排,同时满足这些条件. 思路: 最大流求二分图多重匹配.建立超级源点S.超级汇点T.对于每一个学生i,连一条从S到i的容量为a_i的边.对于每一项比赛i,连一条从i到T的容量为m_i的边.对于每一个学生i和其所擅长的所有比赛j,连一条从i到j的容量为1的边.计算最大流F,当F=Σm_i时,条件满足.

POJ--3308--Paratroopers【Dinic】二分图顶点覆盖+网络最大流

链接:http://poj.org/problem?id=3308 题意:未来世界火星人要入侵地球,他们要派一些伞兵来摧毁地球的兵工厂,兵工厂可以视为一个m*n的矩阵,现在知道了他们每个伞兵的降落位置.为了粉碎火星人的阴谋,我们需要在某行或某列来架一个机关枪来消灭一整行或一整列的火星人,但是在这需要一定的花费,告诉每行及每列架机关枪的花费,总花费是每行及每列的花费相乘.求使得火星人全部被消灭的最小花费. 思路:需要消灭所有敌人,是二分图最小点权覆盖问题,要覆盖所有的边并使花费最小,即求最小割,根

二分图最佳匹配,求最大权匹配或最小权匹配

Beloved Sons http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1338 题意:国王有N个儿子,现在每个儿子结婚都能够获得一定的喜悦值,王子编号为1-N,有N个女孩的编号同样为1-N,每个王子心中都有心仪的女孩,现在问如果安排,能够使得题中给定的式子和最大. 分析:其实题目中那个开根号是个烟雾弹,只要关心喜悦值的平方即可.那么对王子和女孩之间构边,边权为喜悦值的平方,对于每一个王子虚拟出一个女孩边权为0,这样是为了所

[二分图初步]【模板】二分图匹配

题目链接 题目简述:就是二分图板子. Q:什么是二分图呢? A:二分图就是一个无向图可以分成两个子集,且满足这个图中每条边的端点都是属于不同子集的. 什么意思呢?上面这个看起来好像有点晦涩难懂,其实这个可以很好地用生活来解释.在现实生活中,每个班级都有那么几对“关系异常”的男女.我们将整个年级中所有这样的人拉出来站在一起,如果发现没有一对是同性的(笑),那么就说明这是一群符合大众道德观(我不歧视同性恋)的早恋学生,那么可以说这群人是符合二分图的定义的.这相当于所有人是一个图,他们之间的情愫就是将

匈牙利算法求二分图的最大匹配数

给定一个二分图,其中左半部包含n1n1个点(编号1~n1n1),右半部包含n2n2个点(编号1~n2n2),二分图共包含m条边. 数据保证任意一条边的两个端点都不可能在同一部分中. 请你求出二分图的最大匹配数. 二分图的匹配:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配. 二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数. 输入格式 第一行包含三个整数 n1n1. n2n2 和 mm. 接下

poj 2400 Supervisor, Supervisee KM求二分图+dfs输出所有解

题意: 有n个Supervisor和Supervisee,他们之间相互有一个评分,现在要求一个匹配,所有人的评分和最小,并输出使评分和最小的所有匹配方案. 分析: KM算法求二分图的最小权匹配,并用dfs输出所有方案. 代码: //poj 2400 //sep9 #include <iostream> using namespace std; const int maxN=16; char g[maxN][maxN]; int mx[maxN],my[maxN],hx[maxN],hy[max

POJ-2195 Going Home---KM算法求最小权值匹配(存负边)

题目链接: https://vjudge.net/problem/POJ-2195 题目大意: 给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致.man每移动一格需花费$1(即单位费用=单位距离),一间house只能入住一个man.现在要求所有的man都入住house,求最小费用. 思路: KM算法传送门: 理解篇    运用篇 每个man和house建立带权二分图,曼哈顿距离就是边的值,这里要求最小费用,也就是二分图最小权值匹配,但是KM算法求的是二分图最

用三个函数分别实现求三角形,正方形,圆形面积(所有底高半径都由用户 输入);在主函数中,通过用户不同的选择分别进行调用;

/*2.用三个函数分别实现求三角形,正方形,圆形面积(所有底高半径都由用户输入):在主函数中,通过用户不同的选择分别进行调用:*/ #include <stdio.h>#define P 3.14double sanjiao(double di,double gao){ double mianji = (di * gao)/2 ; return mianji;} double zhengfangxing(double bian){ double mianji2 = bian*bian; ret