描述

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

小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"。

提示:二分图多重匹配

小Ho:真是麻烦啊,要不让他们自己报名项目怎么样?

小Hi:那样可能满足不了人数的要求啊,还是根据他们的意愿来进行分配吧。

小Ho:要是每个项目都只要派一个人参加就好了。这样只需要一个简单的二分图匹配就可以决定了!

小Hi:但是现在的情况是一个人可以参加多个项目,一个项目也需要多个人参加才行。

小Ho:对啊,所以这就问题所在啊。小Hi你有什么解决的办法么?

小Hi:嗯......有了!

小Ho:什么办法?

小Hi:还是从你刚刚说的二分图匹配入手,我们仍然将学生看作A部,比赛项目看作B部:

接下来,根据每个学生的意愿我们将对应的A[i]和B[j]连起来。比如编号为i的学生擅长编号为j的项目,那么就连接A[i]-B[j]:

小Ho:然后呢?

小Hi:这次的问题和二分匹配不同的地方在于:匹配结果中,A[i]可能和多个B[j]相连,如果有一个可以来记录A[i]连接数量的量呢?

小Ho:记录A[i]的连接数量么?

小Hi:对!因为A[i]最多只能和a[i]的点相连。所以我们需要一个方法来限制这个量在0~a[i]之间变动。

小Ho:这听上去有点像网络流里面的流量,只能在0和容量之间变动。

小Hi:没错!这里我们要用的就是网络流。

小Ho:那具体怎么做呢?

小Hi:我们需要对之前的二分图进行进一步扩展。首先虚拟一个源点s和汇点t:

接下来我们根据a[i],在s和A[i]之间连接一条容量为a[i]的边。

同时将原来A[i]-B[j]直接的边都改造为从A[i]到B[j]的容量为1的边。

最后我们还要连接所有的B[j]-t。由于比赛项目B[j]最多只需要m[j]名选手参加,所以我们不妨限制B[j]-t的容量为m[j]。

这就是我们最后的网络流图。那么小Ho,你想想在这个图上面做的最大流有什么含义?

小Ho:我想想啊......我知道了!

在完成最大流后,这个网络流图的流量情况直接对应了一个分配方案:

s-A[i]:这一类边的流量表示了A[i]参加的项目数量。

A[i]-B[j]:这一类边的流量表示了A[i]是否参加项目B[j],若参加则流量为1,否则流量为0。

B[j]-t:这一类边的流量表示了参加比赛项目B[j]的选手数量。

由于流网络会自动调整去满足最大流量,所以它会自动调整每个A[i]-B[j]的流量来使得B[j]-t尽可能大。

若每个项目都能够满足人数的话,网络流会自己调整为所有B[j]-t都满流的情况。

小Hi:就是这样,我们只需要最后判断一下每一条B[j]-t的边是否满流,就可以知道能否满足需求。同时还可以根据A[i]-B[j]的情况,计算出每个选手所参加的比赛项目。

小Ho:这个方法好厉害,都不需要自己手动去进行调整了。

小Hi:没错,这也就是网络流的神奇之处。对于这类允许多条边的匹配问题,也被称为二分图多重匹配问题。而网络流正是它的一个简单解决方法。

#include <bits/stdc++.h>
using namespace std; #define maxn 505
#define INF 0x3f3f3f3f struct Edge
{
int from,to,cap,flow;
}; struct Dinic
{
int n,m,s,t;
vector<Edge> edge;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn]; void init()
{
for(int i=;i<maxn;i++)
G[i].clear();
edge.clear();
memset(d,,sizeof(d));
memset(vis,,sizeof(vis));
memset(cur,,sizeof(cur));
} void addEdge (int from,int to,int cap)
{
edge.push_back((Edge){from,to,cap,});
edge.push_back((Edge){to,from,,});
m = edge.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS()
{
memset(vis,,sizeof(vis));
queue<int> Q;
Q.push(s);
d[s] = ;
vis[s] = ;
while(!Q.empty())
{
int x = Q.front();
Q.pop();
for(int i=; i<G[x].size(); i++)
{
Edge & e = edge[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to] = ;
d[e.to] = d[x] + ;
Q.push(e.to);
}
}
}
return vis[t];
} long long DFS(int x,int a)
{
if(x==t||a==) return a;
long long flow = ,f;
for(int & i = cur[x]; i<G[x].size(); i++)
{
Edge & e = edge[G[x][i]];
if(d[x] + ==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>)
{
e.flow +=f;
edge[G[x][i]^].flow -=f;
flow +=f;
a-=f;
if(a==) break;
}
}
return flow;
} int Maxflow (int s,int t) {
this->s = s;this->t = t;
int flow = ;
while(BFS()) {
memset(cur,,sizeof(cur));
flow+=DFS(s,INF);
}
return flow;
} //求最小割S,T;
void new_BFS(int s,int n)
{
memset(vis,,sizeof(vis));
d[s] = ;
vis[s] = ;
queue<int> Q;
Q.push(s);
while(!Q.empty())
{
int u = Q.front();
Q.pop(); for(int i=;i<G[u].size();i++)
{
Edge & e = edge[G[u][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to] = ;
d[e.to] = d[u] + ;
Q.push(e.to);
}
}
} int cnt = ;
for(int i=;i<=n;i++)
{
if(vis[i]) cnt++;
}
printf("%d\n",cnt);
for(int i=;i<=n;i++)
if(vis[i]) printf("%d ",i);
puts("");
} }sol; int main()
{ int t;
scanf("%d",&t);
while(t--)
{
sol.init();
int n,m;
long long sum = ;
scanf("%d%d",&n,&m);
int s=,t=n+m+;
for(int i=;i<=m;i++)
{
int cap;
scanf("%d",&cap);
sum+=cap;
sol.addEdge(n+i,t,cap);
}
for(int i=;i<=n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
sol.addEdge(,i,a);
for(int j=;j<b;j++)
{
int to;
scanf("%d",&to);
sol.addEdge(i,n+to,); ///容量为1
}
}
//cout<<sol.Maxflow(s,t)<<endl;
if(sol.Maxflow(s,t)!=sum) puts("No");
else puts("Yes");
}
return ;
}

之前做过二分图的多重匹配。用的匈牙利,将match加一维成为二维的。加一个cnt数组记录B块匹配了多少。

现在这里变得复杂了,就是每个人可以选多个。

网络流来了,不知道哪个AK大神说的,一切图论皆网络流。

怎么建图:

S到A的容量是ca,B到t的容量是cb,A到B的连线的容量是1。

重点来了,是否B都可以匹配好,就是网络流的最大流是否等于cb的总和。

hiho 第117周 二分图多重匹配,网络流解决的更多相关文章

  1. POJ3189_Steady Cow Assignment(二分图多重匹配/网络流+二分构图)

    解题报告 http://blog.csdn.net/juncoder/article/details/38340447 题目传送门 题意: B个猪圈,N头猪.每头猪对每一个猪圈有一个惬意值.要求安排这 ...

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

    #1393 : 网络流三·二分图多重匹配 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 学校的秋季运动会即将开始,为了决定参赛人员,各个班又开始忙碌起来. 小Hi和小H ...

  3. 网络流24题 第五题 - PowerOJ1740 CodeVS1905 圆桌问题 二分图多重匹配 网络最大流

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - PowerOJ1740 - 有SPJ - 推荐 题目传送门 - CodeVS1905 - 无SPJ - 0% ...

  4. 【网络流24题】No.7 试题库问题 (最大流,二分图多重匹配)

    [题意] 假设一个试题库中有 n 道试题. 每道试题都标明了所属类别. 同一道题可能有多个类别属性.现要从题库中抽取 m 道题组成试卷.并要求试卷包含指定类型的试题. 试设计一个满足要求的组卷算法. ...

  5. [HihoCoder1393]网络流三·二分图多重匹配

    题目大意: 班级有$N$名学生,运动会有$M$项不同的比赛,第$i$项比赛每个班需要派出$m_i$名选手参加,编号为i的学生最多同时参加给定的$b_i$项比赛中的任意$a_i$项比赛.根据统计的结果, ...

  6. 稳定的奶牛分配 && 二分图多重匹配+二分答案

    题意: 农夫约翰有N(1<=N<=1000)只奶牛,每只奶牛住在B(1<=B<=20)个奶牛棚中的一个.当然,奶牛棚的容量有限.有些奶牛对它现在住的奶牛棚很满意,有些就不太满意 ...

  7. poj 2289 Jamie's Contact Groups【二分+最大流】【二分图多重匹配问题】

    题目链接:http://poj.org/problem?id=2289 Jamie's Contact Groups Time Limit: 7000MS   Memory Limit: 65536K ...

  8. kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树

    二分匹配:二分图的一些性质 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j ...

  9. <转> 二分图多重匹配问题

    在二分图最大匹配中,每个点(不管是X方点还是Y方点)最多只能和一条匹配边相关联,然而,我们经常遇到这种问题,即二分图匹配中一个点可以和多条匹配边相关联,但有上限,或者说,Li表示点i最多可以和多少条匹 ...

随机推荐

  1. how to use automapper in c#, from cf~

    [DataContract] public class GroupDto { [DataMember] public int id { get; set; } [DataMember] public ...

  2. ACM常用算法及练习(1)

    ACM常用算法及练习 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来. 1.最短 ...

  3. Nopi .net下面的Excel第三方dll

    相关参考资料:1.npoi官网:http://npoi.codeplex.com/2.用NPOI操作EXCEL--插入图片:  http://www.cnblogs.com/atao/archive/ ...

  4. 封装mysqli类

    类: <?phpheader('content-type:text/html;charset=utf-8');/*掌握满足单例模式的必要条件(1)私有的构造方法-为了防止在类外使用new关键字实 ...

  5. (七)DAC0832 数模转换芯片的应用 以及运算放大器的学习 01

    DAC0832是8分辨率的D/A转换集成芯片.与微处理器完全兼容.这个DA芯片以其价格低廉.接口简单.转换控制容易等优点,在单片机应用系统中得到广泛的应用.D/A转换器由8位输入锁存器.8位DAC寄存 ...

  6. linux tomcat 配置

    http://www.cnblogs.com/xdp-gacl/p/4097608.html

  7. Windows服务安装异常:System.Security.SecurityException: 未找到源,但未能搜索某些或全部事件日志。不可 访问的日志: Security

    Windows服务安装异常:System.Security.SecurityException: 未找到源,但未能搜索某些或全部事件日志.不可 访问的日志: Security 2种方法处理: 一.右键 ...

  8. 夺命雷公狗—angularjs—25—angular内置的方法(高级)

    查看版本信息 angular.version console.log(angular.version); 判断是否相等 angular.equals() var str1 = ''; var str2 ...

  9. windows下快速启动 nginx 和 php-cgi 的两个批处理

    这是启动的批处理: set nginx=D:\nginx-1.9.5\ set php=D:\php\ start /MIN %nginx%nginx.exe start /MIN %php%php- ...

  10. 关于陈冰、陈良乔以及《我的第一本C++书》【转】

    出处:如何在淘宝上卖出 600 本自己写的 C++ 入门书? 陈冰:<我的第一本C++书> 策划编辑,现为图灵公司副总编,<C程序设计伴侣>策划编辑 陈良乔:<我的第一本 ...